From 968b87760ba87e501edece7a81a266bb9b3276c3 Mon Sep 17 00:00:00 2001 From: SecurosysFernandez <96186827+SecurosysFernandez@users.noreply.github.com> Date: Fri, 17 Nov 2023 09:22:04 +0100 Subject: [PATCH 01/16] Added License file --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..29f81d8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From 65b72ea9acf7a368e156aeb36f76037e51ddf1b1 Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Fri, 17 Nov 2023 09:22:12 +0100 Subject: [PATCH 02/16] Release v.1.0.2 --- .github/ISSUE_TEMPLATE/bug-report-sse.md | 49 + .github/ISSUE_TEMPLATE/feature-request-sse.md | 33 + .gitignore | 4 + LICENSE | 201 ++ Makefile | 165 + Readme.md | 983 ++++++ backend/backend.go | 139 + backend/go.mod | 62 + backend/go.sum | 223 ++ backend/path_config.go | 274 ++ backend/path_help.go | 425 +++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 ++ backend/path_hsm_key_bls.go | 259 ++ backend/path_hsm_key_camellia.go | 226 ++ backend/path_hsm_key_chacha20.go | 208 ++ backend/path_hsm_key_dsa.go | 273 ++ backend/path_hsm_key_ec.go | 270 ++ backend/path_hsm_key_ed.go | 271 ++ backend/path_hsm_key_import.go | 306 ++ backend/path_hsm_key_rsa.go | 273 ++ backend/path_hsm_key_tdea.go | 208 ++ backend/path_hsm_key_with_name.go | 295 ++ backend/path_hsm_keys.go | 1359 ++++++++ backend/path_hsm_operations.go | 1631 ++++++++++ backend/path_hsm_requests.go | 298 ++ client/client.go | 48 + client/client_tsb.go | 1011 ++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + etc/example/policy.json | 93 + etc/release_notes/Release_Notes.md | 13 + go.mod | 22 + go.sum | 2754 +++++++++++++++++ helpers/consts.go | 53 + helpers/functions.go | 191 ++ helpers/go.mod | 57 + helpers/go.sum | 223 ++ helpers/structs.go | 315 ++ project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 ++ testHelpers/test_client_tsb.go | 151 + testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 +++++ tests/go.mod | 66 + tests/go.sum | 223 ++ tests/path_config_test.go | 153 + tests/path_hsm_key_aes_test.go | 133 + tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 + tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 + tests/path_hsm_key_tdea_test.go | 136 + tests/path_hsm_key_using_type_name_test.go | 245 ++ tests/path_hsm_keys_rotation_test.go | 836 +++++ tests/path_hsm_keys_test.go | 312 ++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++ tests/path_hsm_operations_sign_test.go | 647 ++++ tests/path_hsm_operations_unwrap_test.go | 675 ++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++ tests/path_hsm_operations_wrap_test.go | 242 ++ tests/path_hsm_requests_test.go | 299 ++ 69 files changed, 22666 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-sse.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-sse.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/structs.go create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go diff --git a/.github/ISSUE_TEMPLATE/bug-report-sse.md b/.github/ISSUE_TEMPLATE/bug-report-sse.md new file mode 100644 index 0000000..40777e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-sse.md @@ -0,0 +1,49 @@ +--- +name: Bug report SSE +about: Create a report to help us improve +title: "[BUG] " +labels: '' +assignees: Peter-FNet + +--- + + + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment:** +* Vault Server Version (retrieve with `vault status`): +* Vault CLI Version (retrieve with `vault version`): +* Server Operating System/Architecture: + +Vault server configuration file(s): + +```hcl +# Paste your Vault config here. +# Be sure to scrub any sensitive values +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request-sse.md b/.github/ISSUE_TEMPLATE/feature-request-sse.md new file mode 100644 index 0000000..8264e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-sse.md @@ -0,0 +1,33 @@ +--- +name: Feature request SSE +about: Suggest an idea for this project +title: "[FEAT]" +labels: '' +assignees: Peter-FNet + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Explain any additional use-cases** +If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5375b60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +builds +vault +deploy +.gitlab-ci.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c770381 --- /dev/null +++ b/Makefile @@ -0,0 +1,165 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + echo "Finished!"; + + +build: + go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 15m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4e0e8f6 --- /dev/null +++ b/Readme.md @@ -0,0 +1,983 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Appendix +### Frequently Asked Questions + +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..92d0f39 --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,139 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..7dba7ce --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,274 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "io/ioutil" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := ioutil.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} + diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..a26e88a --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,425 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + + + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} \ No newline at end of file diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..dca8ab1 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} \ No newline at end of file diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..41d1aa7 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} \ No newline at end of file diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..3025b53 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1011 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + `+passwordString+` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + `+passwordString+` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString:=""; + if(len(keyToBeWrappedPasswordJson)>2){ + keyToBeWrappedPasswordString=`"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString:=""; + if(len(wrapKeyPasswordJson)>2){ + wrapKeyPasswordString=`"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + `+keyToBeWrappedPasswordString+` + "wrapKeyName": "` + wrapKeyName + `", + `+wrapKeyPasswordString+` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + `+passwordString+` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + `+passwordString+` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + `+passwordString+` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + `+passwordString+` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + `+passwordString+` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + `+passwordString+` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + `+passwordString+` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + `+passwordString+` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + `+passwordString+` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + `+passwordString+` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + `+passwordString+` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + `+passwordString+` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString:=""; + if(len(charsNewPasswordJson)>2){ + newPasswordString=`"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + `+passwordString+newPasswordString+` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + `+passwordString+` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + `+passwordString+` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + `+passwordString+` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..8e00e02 --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,93 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..d759deb --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,13 @@ +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d7aecd8 --- /dev/null +++ b/go.mod @@ -0,0 +1,22 @@ +module secretengine + +go 1.16 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers +replace securosys.ch/tests => ./tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8938e00 --- /dev/null +++ b/go.sum @@ -0,0 +1,2754 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20221206110420-d395f97c4830/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= +github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20221215162035-5330a85ea652/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v56.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= +github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= +github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= +github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= +github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.9.3/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.9.4/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.9.6/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.10.0-rc.7/go.mod h1:ILuwjA+kNW+MrN/w5un7n3mTqkwsFu4Bp05/okFUZlE= +github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= +github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk= +github.com/alexflint/go-filemutex v1.2.0/go.mod h1:mYyQSWvw9Tx2/H2n9qXPb52tTYfE0pZAWcBq5mK025c= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220418222510-f25a4f6275ed/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.43.16/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/bytecodealliance/wasmtime-go v0.36.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI= +github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/container-orchestrated-devices/container-device-interface v0.5.4/go.mod h1:DjE95rfPiiSmG7uVXtg0z6MnPm/Lx4wxKCIts0ZE0vg= +github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= +github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= +github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= +github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/btrfs/v2 v2.0.0/go.mod h1:swkD/7j9HApWpzl8OHfrHNxppPd9l44DFZdF94BUj9k= +github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/containerd/cgroups/v3 v3.0.1/go.mod h1:/vtwk1VXrtoa5AaZLkypuOJgA/6DyPMZHJPGQNtlHnw= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= +github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= +github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= +github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= +github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= +github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= +github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s= +github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE= +github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0= +github.com/containerd/containerd v1.6.8/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0= +github.com/containerd/containerd v1.6.9/go.mod h1:XVicUvkxOrftE2Q1YWUXgZwkkAxwQYNOFzYWvfVfEfQ= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= +github.com/containerd/continuity v0.2.2/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= +github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= +github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk= +github.com/containerd/go-cni v1.1.0/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA= +github.com/containerd/go-cni v1.1.3/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA= +github.com/containerd/go-cni v1.1.6/go.mod h1:BWtoWl5ghVymxu6MBjg79W9NZrCRyHIdUtk4cauMe34= +github.com/containerd/go-cni v1.1.9/go.mod h1:XYrZJ1d5W6E2VOvjffL3IZq0Dz6bsVlERHbekNK90PM= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= +github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= +github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow= +github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms= +github.com/containerd/imgcrypt v1.1.3/go.mod h1:/TPA1GIDXMzbj01yd8pIbQiLdQxed5ue1wb8bP7PQu4= +github.com/containerd/imgcrypt v1.1.4/go.mod h1:LorQnPtzL/T0IyCeftcsMEO7AqxUDbdO8j/tSUpgxvo= +github.com/containerd/imgcrypt v1.1.7/go.mod h1:FD8gqIcX5aTotCtOmjeCsi3A1dHmTZpnMISGKSczt4k= +github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= +github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/nri v0.3.0/go.mod h1:Zw9q2lP16sdg0zYybemZ9yTDy8g7fPCIB3KXOGlggXI= +github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM= +github.com/containerd/stargz-snapshotter/estargz v0.12.1/go.mod h1:12VUuCq3qPq4y8yUW+l5w3+oXV3cx2Po3KSe/SmPGqw= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= +github.com/containerd/ttrpc v1.1.1-0.20220420014843-944ef4a40df3/go.mod h1:YYyNVhZrTMiaf51Vj6WhAJqJw+vl/nzABhj8pWrzle4= +github.com/containerd/ttrpc v1.2.1/go.mod h1:sIT6l32Ph/H9cvnJsfXM5drIVzTr5A2flTf1G5tYZak= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containerd/typeurl/v2 v2.1.0/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= +github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= +github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= +github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y= +github.com/containernetworking/cni v1.1.1/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= +github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= +github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= +github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= +github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNBDZcxSOplJT5ico8/FLE= +github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8= +github.com/containernetworking/plugins v1.2.0/go.mod h1:/VjX4uHecW5vVimFa1wkG4s+r/s9qIfPdqlLF4TW8c4= +github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= +github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= +github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/containers/ocicrypt v1.1.3/go.mod h1:xpdkbVAuaH3WzbEabUd5yDsl9SwJA5pABH85425Es2g= +github.com/containers/ocicrypt v1.1.6/go.mod h1:WgjxPWdTJMqYMjf3M6cuIFFA1/MpyyhIM99YInA+Rvc= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= +github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= +github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M= +github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/distribution/distribution/v3 v3.0.0-20220526142353-ffbd94cbe269/go.mod h1:28YO/VJk9/64+sTGNuYaBjWxrXTPrj0C0XmgTIOjxX4= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.20+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.20+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= +github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/foxcpp/go-mockdns v0.0.0-20210729171921-fb145fc6f897/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-ini/ini v1.66.6/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/cel-go v0.12.6/go.mod h1:Jk7ljRzLBhkmiAwBoUxB1sZSCVBAzkqPF25olK/iRDw= +github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= +github.com/google/go-containerregistry v0.13.0/go.mod h1:J9FQ+eSS4a1aC2GNZxvNpbWhgp0487v+cgiilB4FqDo= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= +github.com/intel/goresctrl v0.3.0/go.mod h1:fdz3mD85cmP9sHD8JUlrNWAxvwM86CrbmVXltEKd7zk= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= +github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= +github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= +github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= +github.com/lestrrat-go/jwx v1.2.25/go.mod h1:zoNuZymNl5lgdcu6P7K6ie2QRll5HVfF4xwxBBK1NxY= +github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= +github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= +github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/networkplumbing/go-nft v0.2.0/go.mod h1:HnnM+tYvlGAsMU7yoYwXEVLLiDW9gdMmb5HoGcwpuQs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= +github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= +github.com/onsi/ginkgo/v2 v2.6.1/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= +github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= +github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= +github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= +github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk= +github.com/open-policy-agent/opa v0.42.2/go.mod h1:MrmoTi/BsKWT58kXlVayBb+rYVeaMwuBm3nYAN3923s= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runc v1.1.4/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.1.0-rc.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626/go.mod h1:BRHJJd0E+cx42OybVYSgUvZmU0B8P9gZuRXlZUP7TKI= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/peterh/liner v0.0.0-20170211195444-bf27d3ba8e1d/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/safchain/ethtool v0.2.0/go.mod h1:WkKB1DnNtvsMlDmQ50sgwowDJV/hGbJSOvJoEXs1AJQ= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.19.1/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= +github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= +github.com/vektah/gqlparser/v2 v2.4.5/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0= +github.com/veraison/go-cose v1.0.0-rc.1/go.mod h1:7ziE85vSq4ScFTg6wyoMXjucIGOf4JkFEZi/an96Ct4= +github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yashtewari/glob-intersection v0.1.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.5/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v2 v2.305.5/go.mod h1:zQjKllfqfBVyVStbt4FaosoX2iYd8fV/GRy/PbowgP4= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/client/v3 v3.5.5/go.mod h1:aApjR4WGlSumpnJ2kloS75h6aHUmAyaPLjHMxpc7E7c= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/pkg/v3 v3.5.5/go.mod h1:6ksYFxttiUGzC2uxyqiyOEvhAiD0tuIqSZkX3TyPdaE= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/raft/v3 v3.5.5/go.mod h1:76TA48q03g1y1VpTue92jZLr9lIHKUNcYdZOOGyx8rI= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= +go.etcd.io/etcd/server/v3 v3.5.5/go.mod h1:rZ95vDw/jrvsbj9XpTqPrTAB9/kzchVdhRirySPkUBc= +go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0/go.mod h1:h8TWwRAhQpOd0aM5nYsRD8+flnkj+526GEIVlarH7eY= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0/go.mod h1:UMklln0+MRhZC4e3PwmN3pCtq4DyIadWw4yikh6bNrw= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0/go.mod h1:5eCOqeGphOyz6TsY3ZDNjE33SM/TFAK3RGuCL2naTgY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.35.0/go.mod h1:9NiG9I2aHTKkcxqCILhjtyNA1QEiCjdBACv4IvrFQ+c= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU= +go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= +go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= +go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM= +go.opentelemetry.io/otel v1.10.0/go.mod h1:NbvWjCthWHKBEUMpf0/v8ZRZlni86PpGFEMA9pnQSnQ= +go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0/go.mod h1:M1hVZHNxcbkAlcvrOMlpQ4YOO3Awf+4N2dxkZL3xm04= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0/go.mod h1:78XhIg8Ht9vR4tbLNUhXsiOnE2HOuSeKAiAcoVQEpOY= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0/go.mod h1:UFG7EBMRdXyFstOwH028U0sVf+AvukSGhF0g8+dmNG8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0/go.mod h1:ceUgdyfNv4h4gLxHR0WNfDiiVmZFodZhZSbOLhpxqXE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.10.0/go.mod h1:Krqnjl22jUJ0HgMzw5eveuCvFDXY4nSYb4F8t5gdrag= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0/go.mod h1:HrbCVv40OOLTABmOn1ZWty6CHXkU8DK/Urc43tHug70= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0/go.mod h1:E+/KKhwOSw8yoPxSSuUHG6vKppkvhN+S1Jc7Nib3k3o= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.10.0/go.mod h1:OfUCyyIiDvNXHWpcWgbF+MWvqPZiNa3YDEnivcnYsV0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0/go.mod h1:5w41DY6S9gZrbjuq6Y+753e96WfPha5IcsOSZTtullM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0/go.mod h1:+N7zNjIJv4K+DeX67XXET0P+eIciESgaFDBqh+ZJFS4= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/metric v0.30.0/go.mod h1:/ShZ7+TS4dHzDFmfi1kSXMhMVubNoP0oIaBp70J6UXU= +go.opentelemetry.io/otel/metric v0.31.0/go.mod h1:ohmwj9KTSIeBnDBm/ZwH2PSZxZzoOaG2xZeekTRzL5A= +go.opentelemetry.io/otel/metric v0.37.0/go.mod h1:DmdaHfGt54iV6UKxsV9slj2bBRJcKC1B1uvDLIioc1s= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI= +go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= +go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU= +go.opentelemetry.io/otel/sdk v1.10.0/go.mod h1:vO06iKzD5baltJz1zarxMCNHFpUlUiOy4s65ECtn6kE= +go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk= +go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk= +go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= +go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4= +go.opentelemetry.io/otel/trace v1.10.0/go.mod h1:Sij3YYczqAdz+EhmGhE6TpTxUO5/F/AzrK+kxfGqySM= +go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg= +go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220405210540-1e041c57c461/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= +k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= +k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= +k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= +k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= +k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= +k8s.io/apimachinery v0.25.0/go.mod h1:qMx9eAk0sZQGsXGu86fab8tZdffHbwUfsvzqKn4mfB0= +k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= +k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= +k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ= +k8s.io/apiserver v0.26.2/go.mod h1:GHcozwXgXsPuOJ28EnQ/jXEM9QeG6HT22YxSNmpYNh8= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= +k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= +k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= +k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= +k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= +k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= +k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI= +k8s.io/component-base v0.26.2/go.mod h1:DxbuIe9M3IZPRxPIzhch2m1eT7uFrSBJUBuVCQEBivs= +k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= +k8s.io/cri-api v0.23.1/go.mod h1:REJE3PSU0h/LOV1APBrupxrEJqnoxZC8KWzkBUHwrK4= +k8s.io/cri-api v0.25.0/go.mod h1:J1rAyQkSJ2Q6I+aBMOVgg2/cbbebso6FNa0UagiR0kc= +k8s.io/cri-api v0.25.3/go.mod h1:riC/P0yOGUf2K1735wW+CXs1aY2ctBgePtnnoFLd0dU= +k8s.io/cri-api v0.26.2/go.mod h1:Oo8O7MKFPNDxfDf2LmrF/3Hf30q1C6iliGuv3la3tIA= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kms v0.26.2/go.mod h1:69qGnf1NsFOQP07fBYqNLZklqEHSJF024JqYCaeVxHg= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= +modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= +oras.land/oras-go v1.2.0/go.mod h1:pFNs7oHp2dYsYMSS82HaX5l4mpnGO7hbpPN6EWH2ltc= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.35/go.mod h1:WxjusMwXlKzfAs4p9km6XJRndVt2FROgMVCE4cdohFo= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..1925e0e --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,191 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9249056 --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,315 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..eee800f --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.0.2 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..b55e030 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_API_URL", + "auth": "TOKEN", + "bearertoken": "TSB_BEARER_TOKEN", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} From 28b64c71232a935f3562d0e37e17cb06571f3f4e Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Tue, 28 Nov 2023 14:57:25 +0100 Subject: [PATCH 03/16] Release v.1.0.3 --- .gitignore | 7 + LICENSE.txt | 201 ++ Makefile | 197 ++ Readme.md | 983 ++++++++++ backend/backend.go | 140 ++ backend/go.mod | 62 + backend/go.sum | 223 +++ backend/path_config.go | 274 +++ backend/path_help.go | 425 +++++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 +++ backend/path_hsm_key_bls.go | 259 +++ backend/path_hsm_key_camellia.go | 225 +++ backend/path_hsm_key_chacha20.go | 208 +++ backend/path_hsm_key_dsa.go | 273 +++ backend/path_hsm_key_ec.go | 270 +++ backend/path_hsm_key_ed.go | 271 +++ backend/path_hsm_key_import.go | 306 ++++ backend/path_hsm_key_rsa.go | 273 +++ backend/path_hsm_key_tdea.go | 208 +++ backend/path_hsm_key_with_name.go | 295 +++ backend/path_hsm_keys.go | 1359 ++++++++++++++ backend/path_hsm_operations.go | 1631 +++++++++++++++++ backend/path_hsm_requests.go | 298 +++ backend/path_mariadb_integration.go | 609 ++++++ client/client.go | 48 + client/client_tsb.go | 1011 ++++++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + .../alpine3/docker-compose-alpine3.yml | 56 + docker-builder/build-in-docker.sh | 12 + etc/example/policy.json | 97 + etc/release_notes/Release_Notes.md | 20 + go.mod | 80 + go.sum | 254 +++ go.work | 8 + go.work.sum | 164 ++ helpers/consts.go | 53 + helpers/functions.go | 234 +++ helpers/go.mod | 57 + helpers/go.sum | 223 +++ helpers/mariadb_structs.go | 82 + helpers/structs.go | 315 ++++ integrationTests/client/client.go | 30 + integrationTests/client/client_config.go | 15 + integrationTests/client/go.mod | 24 + integrationTests/client/go.sum | 58 + integrationTests/docker/docker-compose.yml | 39 + .../docker/docker-files/MariaDB_Dockerfile | 2 + .../docker/mysql-config/hashicorp.cnf | 18 + .../tests/a_enable_plugin_test.go | 48 + .../tests/b_config_plugin_test.go | 55 + .../tests/c_create_aes_key_test.go | 234 +++ .../tests/c_create_key_by_keyname_test.go | 93 + .../tests/c_create_rsa_key_test.go | 250 +++ .../tests/c_create_smart_rsa_key_test.go | 255 +++ .../tests/d_operations_on_key_test.go | 329 ++++ integrationTests/tests/go.mod | 6 + integrationTests/tests/go.sum | 0 integration_junit_report.xml | 54 + junit_report.xml | 297 +++ project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 +++ testHelpers/test_client_tsb.go | 151 ++ testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 ++++++++ tests/go.mod | 66 + tests/go.sum | 223 +++ tests/go.work | 5 + tests/go.work.sum | 163 ++ tests/path_config_test.go | 153 ++ tests/path_hsm_key_aes_test.go | 133 ++ tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 ++ tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 ++ tests/path_hsm_key_tdea_test.go | 136 ++ tests/path_hsm_key_using_type_name_test.go | 245 +++ tests/path_hsm_keys_rotation_test.go | 836 +++++++++ tests/path_hsm_keys_test.go | 312 ++++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++++ tests/path_hsm_operations_sign_test.go | 647 +++++++ tests/path_hsm_operations_unwrap_test.go | 675 +++++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++++++++ tests/path_hsm_operations_wrap_test.go | 242 +++ tests/path_hsm_requests_test.go | 299 +++ tests/path_mariadb_integration_test.go | 78 + 94 files changed, 23215 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.txt create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 backend/path_mariadb_integration.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 docker-builder/alpine3/docker-compose-alpine3.yml create mode 100644 docker-builder/build-in-docker.sh create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 go.work create mode 100644 go.work.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/mariadb_structs.go create mode 100644 helpers/structs.go create mode 100644 integrationTests/client/client.go create mode 100644 integrationTests/client/client_config.go create mode 100644 integrationTests/client/go.mod create mode 100644 integrationTests/client/go.sum create mode 100644 integrationTests/docker/docker-compose.yml create mode 100644 integrationTests/docker/docker-files/MariaDB_Dockerfile create mode 100644 integrationTests/docker/mysql-config/hashicorp.cnf create mode 100644 integrationTests/tests/a_enable_plugin_test.go create mode 100644 integrationTests/tests/b_config_plugin_test.go create mode 100644 integrationTests/tests/c_create_aes_key_test.go create mode 100644 integrationTests/tests/c_create_key_by_keyname_test.go create mode 100644 integrationTests/tests/c_create_rsa_key_test.go create mode 100644 integrationTests/tests/c_create_smart_rsa_key_test.go create mode 100644 integrationTests/tests/d_operations_on_key_test.go create mode 100644 integrationTests/tests/go.mod create mode 100644 integrationTests/tests/go.sum create mode 100644 integration_junit_report.xml create mode 100644 junit_report.xml create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/go.work create mode 100644 tests/go.work.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go create mode 100644 tests/path_mariadb_integration_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3badb78 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +builds +test + +vault_exec + +deploy +.gitlab-ci.yml diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..88c63bc --- /dev/null +++ b/Makefile @@ -0,0 +1,197 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + make release-alpine3 + echo "Finished!"; + +release-alpine3: + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-amd64 + make clean-docker-builder IMAGE=amd64/golang + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-i386 + make clean-docker-builder IMAGE=i386/golang + +clean-docker-builder: + @if [ "$$(docker images | grep '$(IMAGE)')" != "" ]; then \ + docker rmi -f $$(docker images | grep '$(IMAGE)' | awk '{ print $$3}') 2> /dev/null || true ; \ + fi; + docker volume prune -f + docker container prune -f + +run-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml up --build -d +clean-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml down --remove-orphans --rmi all + docker volume prune -f + docker container prune -f + + + +integration-tests: + rm -fr integrationTests/docker/plugins/securosys-hsm + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -o integrationTests/docker/plugins/securosys-hsm cmd/securosys-hsm/main.go + make run-docker-test-container + + sleep 5 + go install github.com/jstemmer/go-junit-report/v2@latest + cd integrationTests/tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}integration_junit_report.xml -set-exit-code + + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..6a06f46 --- /dev/null +++ b/Readme.md @@ -0,0 +1,983 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Appendix +### Frequently Asked Questions + +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..67cf38a --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,140 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + pathMariaDBIntegration(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..7dba7ce --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,274 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "io/ioutil" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := ioutil.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} + diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..a26e88a --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,425 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + + + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..32954d9 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string), map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy, map[string]string{}) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil, map[string]string{}) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString, nil) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..e24fe58 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} diff --git a/backend/path_mariadb_integration.go b/backend/path_mariadb_integration.go new file mode 100644 index 0000000..301aef4 --- /dev/null +++ b/backend/path_mariadb_integration.go @@ -0,0 +1,609 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for create Camellia Keys +func pathMariaDBIntegration(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "keyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + }, + HelpSynopsis: pathKeyCamelliaHelpSynopsis, + HelpDescription: pathKeyCamelliaHelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("version") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathKeyCamelliaHelpSynopsis, + HelpDescription: pathKeyCamelliaHelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathKeyCamelliaHelpSynopsis, + HelpDescription: pathKeyCamelliaHelpDescription, + }, + } +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + rotate := false + if storedSecret != nil { + rotate = true + // return nil, fmt.Errorf("error secret with name: %s exists", name) + } else { + storedSecret = &helpers.MariaDBSecretEntry{} + + } + + keyName := d.Get("keyName").(string) + + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload := b64.StdEncoding.EncodeToString([]byte(helpers.GeneratePassword(32, false, false, false, true))) + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + sysView := b.System() + creator := helpers.Entity{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + creator.Aliases = entity.Aliases + creator.Id = entity.ID + creator.Name = entity.Name + creator.Date = time.Now().UTC() + + } else { + creator.Aliases = nil + creator.Id = "root" + creator.Name = "root" + creator.Date = time.Now().UTC() + + } + var messageAuthenticationCode *string = nil + if result["messageAuthenticationCode"] != nil { + temp := result["messageAuthenticationCode"].(string) + messageAuthenticationCode = &temp + } + var initializationVector *string = nil + if result["initializationVector"] != nil { + temp := result["initializationVector"].(string) + initializationVector = &temp + } + if !rotate { + storedSecret.InitSecret(keyName, keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + } else { + storedSecret.RotateSecret(keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + + } + if err := SetMariaDBSecret(ctx, req.Storage, name, storedSecret); err != nil { + return nil, err + } + + response := map[string]interface{}{} + now := storedSecret.GetActiveVersion().Created.Date + version := storedSecret.GetActiveVersion().Version + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + query := d.Get("query").(string) + params, err := url.ParseQuery(query) + + if query == "" { + str := "" + for key, value := range req.Data { + str = str + key + "=" + value.(string) + "&" + } + str = str[:len(str)-1] + params, err = url.ParseQuery(str) + } + + if err != nil { + return nil, err + } + name := d.Get("name").(string) + + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + if storedSecret == nil { + return nil, fmt.Errorf("error secret with name: %s not exists", name) + } + + version := "1" + if params.Has("version") { + if !strings.Contains(params.Get("version"), "?version=") { + version = storedSecret.CurrentVersion + } else { + parts := strings.Split(params.Get("version"), "?version=") + version = "v" + parts[1] + } + } else { + ver, ok := d.GetOk("version") + if !ok { + return nil, fmt.Errorf("error: missing version") + } + version = ver.(string) + } + + if !params.Has("key_name") { + return nil, fmt.Errorf("key_name query param not exists") + } + keyEntry, err := b.GetKey(ctx, req.Storage, params.Get("key_name")) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + keyName := params.Get("key_name") + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + + if !helpers.ContainsKey(storedSecret.Versions, version) { + return nil, fmt.Errorf("Secret version %s is not exists.", version) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload := storedSecret.GetVersion(version).EncryptedSecret + + if !params.Has("cipher_algorithm") { + return nil, fmt.Errorf("cipher_algorithm query param not exists") + } + + cipherAlgorithm := params.Get("cipher_algorithm") + if keyEntry.KeyTypeName != "aes256-gcm96" && cipherAlgorithm == "" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVectorString := "" + if params.Has("initialization_vector") { + initializationVectorString = params.Get("initialization_vector") + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + passwordString := "" + if params.Has("password") { + passwordString = params.Get("password") + } + tagLengthInt := -1 + if params.Has("tag_length") { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + } + if keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationDataString := "" + if params.Has("aad") { + additionalAuthenticationDataString = params.Get("aad") + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationDataString) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData (param aad) is not valid base64 string") + } + } + client, err := b.GetClient(ctx, req.Storage) + async := false + decrypted := "" + if len(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + async = true + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString, map[string]string{"integration": "MariaDB Encrypt"}) + if errEnc != nil { + return nil, errEnc + } + var resp *helpers.RequestResponse + resp, _, _ = client.GetRequest(requestId) + for resp.Status == "PENDING" { + time.Sleep(1000) + resp, _, _ = client.GetRequest(requestId) + } + if resp.Status != "EXECUTED" { + return nil, fmt.Errorf("error on async decrypt. Expected Status '%s' got '%s'", "EXECUTED", resp.Status) + } + decrypted = resp.Result + + } + } + } + if !async { + resultSync, errEnc := client.Decrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + decrypted = resultSync["payload"].(string) + } + + if cipherAlgorithm == "AES_ECB" || + cipherAlgorithm == "AES_CBC_NO_PADDING" || + cipherAlgorithm == "CAMELLIA_ECB" || + cipherAlgorithm == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + decoded, _ := base64.StdEncoding.DecodeString(decrypted) + response := map[string]interface{}{} + response["data"] = map[string]interface{}{"data": string(decoded)} + now := storedSecret.GetVersion(version).Created.Date + + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} + +// This function helps with saving key in Secrets Engine +func SetMariaDBSecret(ctx context.Context, s logical.Storage, name string, secretEntry *helpers.MariaDBSecretEntry) error { + entry, err := logical.StorageEntryJSON("intergration/mariadb/"+name, secretEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage secret") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetMariaDBSecret(ctx context.Context, s logical.Storage, name string) (*helpers.MariaDBSecretEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "intergration/mariadb/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var secret helpers.MariaDBSecretEntry + + if err := entry.DecodeJSON(&secret); err != nil { + return nil, err + } + return &secret, nil +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..83f9a85 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1011 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + ` + passwordString + ` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy, customMetaData map[string]string) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo, customMetaData) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString := "" + if len(keyToBeWrappedPasswordJson) > 2 { + keyToBeWrappedPasswordString = `"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString := "" + if len(wrapKeyPasswordJson) > 2 { + wrapKeyPasswordString = `"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + ` + keyToBeWrappedPasswordString + ` + "wrapKeyName": "` + wrapKeyName + `", + ` + wrapKeyPasswordString + ` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + ` + passwordString + ` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + ` + passwordString + ` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + ` + passwordString + ` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + ` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString := "" + if len(charsNewPasswordJson) > 2 { + newPasswordString = `"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + newPasswordString + ` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + passwordString + ` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/docker-builder/alpine3/docker-compose-alpine3.yml b/docker-builder/alpine3/docker-compose-alpine3.yml new file mode 100644 index 0000000..1190d88 --- /dev/null +++ b/docker-builder/alpine3/docker-compose-alpine3.yml @@ -0,0 +1,56 @@ + version: "3.3" + services: + golang-builder-alpine3-amd64: + platform: linux/amd64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=amd64 + image: amd64/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-amd64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-i386: + platform: linux/i386 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=386 + image: i386/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-i386 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-arm64: + platform: linux/arm64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=arm64 + image: arm64v8/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-arm64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" \ No newline at end of file diff --git a/docker-builder/build-in-docker.sh b/docker-builder/build-in-docker.sh new file mode 100644 index 0000000..adc15b2 --- /dev/null +++ b/docker-builder/build-in-docker.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd .. +echo "Build ${ARTIFACT_NAME} in ${DOCKER_OS}_${DOCKER_ARCH}"; + cd /src + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; + cd builds; + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; + zip -9 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; + shasum -a 256 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; + cd ..; + rm builds/securosys-hsm; + rm builds/securosys-hsm_SHA256SUM; \ No newline at end of file diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..102a86b --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,97 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value": +"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value": + "replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value": + "replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "TM", + "value": +"replace_me_with_approval_key/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..c16b57c --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,20 @@ +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build/ + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2d78c0c --- /dev/null +++ b/go.mod @@ -0,0 +1,80 @@ +module secretengine + +go 1.21 + +toolchain go1.21.2 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers + +replace securosys.ch/tests => ./tests + +replace securosys.ch/integration/client => ./integrationTests/client + +replace securosys.ch/integration/tests => ./integrationTests/tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/frankban/quicktest v1.14.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afae25d --- /dev/null +++ b/go.sum @@ -0,0 +1,254 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work new file mode 100644 index 0000000..ad36518 --- /dev/null +++ b/go.work @@ -0,0 +1,8 @@ +go 1.21 + +use ( + ./ + ./backend + ./integrationTests/client + ./integrationTests/tests +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..976ca94 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,164 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..bdc47e4 --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "math/rand" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} +func GetVersionNumber(version string) int { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + return versionInt +} +func GetVersionString(version string) string { + return strings.Replace(version, "v", "", 1) +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string, customMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + for key, value := range customMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + specialBytes = "!@#$%^&*()_+-=[]{}\\|;':\",.<>/?`~" + numBytes = "0123456789" + hexDecimalBytes = "0123456789ABCDEF" +) + +func GeneratePassword(length int, useLetters bool, useSpecial bool, useNum bool, useHexadecimal bool) string { + rand.Seed(time.Now().UnixNano()) + b := make([]byte, length) + arrayForRandom := make([]byte, 0) + if useLetters { + arrayForRandom = append(arrayForRandom, letterBytes...) + } + if useSpecial { + arrayForRandom = append(arrayForRandom, specialBytes...) + } + if useNum { + arrayForRandom = append(arrayForRandom, numBytes...) + } + if useHexadecimal { + arrayForRandom = append(arrayForRandom, hexDecimalBytes...) + + } + + for i := range b { + b[i] = arrayForRandom[rand.Intn(len(arrayForRandom))] + } + return string(b) +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/mariadb_structs.go b/helpers/mariadb_structs.go new file mode 100644 index 0000000..97210ac --- /dev/null +++ b/helpers/mariadb_structs.go @@ -0,0 +1,82 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// INTEGRATION MARIADB STRUCTS + +type MariaDBSecretEntry struct { + KeyName string `json:"keyName"` + Versions map[string]MariaDBSecretVersion `json:"secretVersions"` + CurrentVersion string `json:"defaultVersion"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +// Struct of keys stored inside the Vault +type MariaDBSecretVersion struct { + KeyVersion string `json:"keyVersion"` + EncryptedSecret string `json:"encryptedSecret"` + MessageAuthenticationCode *string `json:"messageAuthenticationCode"` + InitializationVector *string `json:"initializationVector"` + Version string `json:"version"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (s *MariaDBSecretEntry) InitSecret(keyName string, keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, creator Entity) { + s.CurrentVersion = "v1" + s.KeyName = keyName + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = "v1" + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = creator + secretVersion.Updated = creator + s.Created = creator + s.Updated = creator + s.Versions = make(map[string]MariaDBSecretVersion) + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) RotateSecret(keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, updater Entity) { + newSecretVersion := GetNewVersion(s.CurrentVersion) + s.CurrentVersion = newSecretVersion + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = newSecretVersion + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = updater + secretVersion.Updated = updater + s.Updated = updater + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) GetActiveVersion() MariaDBSecretVersion { + return s.Versions[s.CurrentVersion] +} +func (s *MariaDBSecretEntry) GetVersion(keyVersion string) MariaDBSecretVersion { + return s.Versions[keyVersion] +} + +// END INTEGRATION MARIADB STRUCTS diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9249056 --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,315 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/integrationTests/client/client.go b/integrationTests/client/client.go new file mode 100644 index 0000000..70d4bee --- /dev/null +++ b/integrationTests/client/client.go @@ -0,0 +1,30 @@ +package integrationClient + +import ( + "fmt" + "log" + "os" + "time" + + "github.com/hashicorp/vault-client-go" +) + +func InitVaultClient() (*vault.Client){ + + // prepare a client with the given base address + client, err := vault.New( + vault.WithAddress(VaultConfig.Url+":"+fmt.Sprint(VaultConfig.Port)), + vault.WithRequestTimeout(30*time.Second), + ) + if err != nil { + log.Fatal(err) + os.Exit(1); + } + + // authenticate with a root token (insecure) + if err := client.SetToken(VaultConfig.RootToken); err != nil { + log.Fatal(err) + os.Exit(1); + } + return client; +} \ No newline at end of file diff --git a/integrationTests/client/client_config.go b/integrationTests/client/client_config.go new file mode 100644 index 0000000..148f2a9 --- /dev/null +++ b/integrationTests/client/client_config.go @@ -0,0 +1,15 @@ +package integrationClient + +type VaultClientConfig struct { + Port int + Url string + RootToken string + SecretsEnginePath string +} + +var VaultConfig VaultClientConfig=VaultClientConfig{ + Port: 8251, + Url: "http://127.0.0.1", + RootToken: "root", + SecretsEnginePath: "securosys-hsm", +} \ No newline at end of file diff --git a/integrationTests/client/go.mod b/integrationTests/client/go.mod new file mode 100644 index 0000000..02d12cd --- /dev/null +++ b/integrationTests/client/go.mod @@ -0,0 +1,24 @@ +module securosys.ch/integration/client + +go 1.21 + +toolchain go1.21.2 + +require github.com/hashicorp/vault-client-go v0.4.2 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stretchr/testify v1.8.2 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect +) diff --git a/integrationTests/client/go.sum b/integrationTests/client/go.sum new file mode 100644 index 0000000..3a52bd0 --- /dev/null +++ b/integrationTests/client/go.sum @@ -0,0 +1,58 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/vault-client-go v0.4.2 h1:XeUXb5jnDuCUhC8HRpkdGPLh1XtzXmiOnF0mXEbARxI= +github.com/hashicorp/vault-client-go v0.4.2/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integrationTests/docker/docker-compose.yml b/integrationTests/docker/docker-compose.yml new file mode 100644 index 0000000..f3d4294 --- /dev/null +++ b/integrationTests/docker/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.0" +name: hashicorp-vault-test-containers +services: + hashicorp-vault-test: + image: hashicorp/vault:latest + container_name: "hashicorp-vault-test" + environment: + VAULT_DEV_ROOT_TOKEN_ID: root + VAULT_ADDR: 'https://0.0.0.0:8251' + VAULT_LOCAL_CONFIG: '{"listener": [{"tcp":{"address": "0.0.0.0:8251","tls_disable":"1"}}], "default_lease_ttl": "168h", "max_lease_ttl": "720h"}, "ui": true}' + volumes: + - ./plugins/:/vault/plugins + cap_add: + - IPC_LOCK + healthcheck: + retries: 5 + ports: + - "8251:8251" + privileged: true + command: server -dev -dev-root-token-id=root -dev-plugin-dir=/vault/plugins + # networks: + # - web + # mariadb-test-integration: + # build: + # dockerfile: ./docker-files/MariaDB_Dockerfile + # container_name: "mariadb-test-integration" + # restart: always + # environment: + # MARIADB_ROOT_PASSWORD: example + # volumes: + # - ./mysql-config:/etc/mysql/conf.d + # - ./db:/var/lib/mysql + # networks: + # - web + +# networks: +# web: +# external: true + \ No newline at end of file diff --git a/integrationTests/docker/docker-files/MariaDB_Dockerfile b/integrationTests/docker/docker-files/MariaDB_Dockerfile new file mode 100644 index 0000000..7e5d37a --- /dev/null +++ b/integrationTests/docker/docker-files/MariaDB_Dockerfile @@ -0,0 +1,2 @@ +FROM mariadb:latest +RUN apt-get update && apt-get install -y mariadb-plugin-hashicorp-key-management diff --git a/integrationTests/docker/mysql-config/hashicorp.cnf b/integrationTests/docker/mysql-config/hashicorp.cnf new file mode 100644 index 0000000..1210099 --- /dev/null +++ b/integrationTests/docker/mysql-config/hashicorp.cnf @@ -0,0 +1,18 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="http://172.17.0.3:8251/v1/securosys-hsm/integrations/mariadb/test_async/?cipher_algorithm=RSA&key_name=rsa_with_policy&version=" +loose-hashicorp-key-management-token="root" +loose-hashicorp-key-management-check-kv-version="off" +loose-hashicorp-key-management-timeout=10 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +loose-hashicorp-key-management-cache-timeout=31556952000 +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = OFF +innodb_encrypt_log = OFF +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 diff --git a/integrationTests/tests/a_enable_plugin_test.go b/integrationTests/tests/a_enable_plugin_test.go new file mode 100644 index 0000000..d16575a --- /dev/null +++ b/integrationTests/tests/a_enable_plugin_test.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "testing" + + "github.com/hashicorp/vault-client-go/schema" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestEnablePlugin(t *testing.T) { + + t.Run("A.1 Test Enable Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.System.MountsEnableSecretsEngine(ctx,integrationClient.VaultConfig.SecretsEnginePath,schema.MountsEnableSecretsEngineRequest{ + Type: "securosys-hsm", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/b_config_plugin_test.go b/integrationTests/tests/b_config_plugin_test.go new file mode 100644 index 0000000..d777766 --- /dev/null +++ b/integrationTests/tests/b_config_plugin_test.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfigPlugin(t *testing.T) { + + t.Run("B.1 Test Config Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/config",testHelpers.ConfigParams) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data["result"]==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s","null").Error()) + } + + if(!strings.Contains(resp.Data["result"].(string),"Connection successful:")){ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s",resp.Data["result"]).Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_aes_key_test.go b/integrationTests/tests/c_create_aes_key_test.go new file mode 100644 index 0000000..ccffd1b --- /dev/null +++ b/integrationTests/tests/c_create_aes_key_test.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateAESKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_aes"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_aes got %s","null").Error()) + } + }) + t.Run("C.3 Read AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["secretKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Key Secret got %s","null").Error()) + } + }) + t.Run("C.8 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_key_by_keyname_test.go b/integrationTests/tests/c_create_key_by_keyname_test.go new file mode 100644 index 0000000..285e47c --- /dev/null +++ b/integrationTests/tests/c_create_key_by_keyname_test.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateKeyByKeyNamePlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with label integrationTestKeyRSAName using name rsa-2048", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/type/rsa-2048/integration_test_key_rsa_name",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSAName", + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSAName"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSAName",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSAName_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test Remove Key RSA Key with name integrationTestKeyRSAName", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa_name",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_rsa_key_test.go b/integrationTests/tests/c_create_rsa_key_test.go new file mode 100644 index 0000000..90c1a10 --- /dev/null +++ b/integrationTests/tests/c_create_rsa_key_test.go @@ -0,0 +1,250 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["publicKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Public Key got %s","null").Error()) + } + if(resp.Data["privateKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Private Key got %s","null").Error()) + } + }) + t.Run("C.8 Update password RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/update-password",map[string]interface{}{ + "password":"", + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Test Remove Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_smart_rsa_key_test.go b/integrationTests/tests/c_create_smart_rsa_key_test.go new file mode 100644 index 0000000..dfdd792 --- /dev/null +++ b/integrationTests/tests/c_create_smart_rsa_key_test.go @@ -0,0 +1,255 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateSmartRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_smart_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_smart_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Block Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/block",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.8 UnBlock Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/unblock",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Update password Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/update-password",map[string]interface{}{ + "password":nil, + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/d_operations_on_key_test.go b/integrationTests/tests/d_operations_on_key_test.go new file mode 100644 index 0000000..8dc951b --- /dev/null +++ b/integrationTests/tests/d_operations_on_key_test.go @@ -0,0 +1,329 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestOperationsOnKeyPlugin(t *testing.T) { + + t.Run("D.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.2 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.3 Test Encrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.4 Test Encrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.5 Test Decrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.6 Test Decrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_key_aes",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.7 Test Sign using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + }) + t.Run("D.8 Test Verify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/verify/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "keyVersion":"v1", + "signatureAlgorithm":"SHA256_WITH_RSA", + "signature":resp.Data["signature"].(string), + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid got %s","null").Error()) + } + if(resp.Data["signatureValid"]==false){ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid %s got %s","true",resp.Data["signatureValid"]).Error()) + } + }) + t.Run("D.9 Test Modify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/modify",map[string]interface{}{ + "simplePolicy":`{"test":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnydX62tLYNF+Op1SRnX6avkkyQWlpYPagH85zxaGnMlZoMioqgjSOCuRvjaP7Y5noPMYayp3gJ2PwLXvw9+JlnL+iwklOcpONSa6gDoCDsk26DOoY0ELEPaGdW61mc2bj2hOQE0GEpPsRywJoRLS3B2e8bqRfAniAfGsUq3MK09iL5YOCuUCHCUiR9iZMSt0+Ek/kE4TrazbOCev1g6Ux2vOyTuQ6mF3wVuqwd8RhfvlNNKXbD2GD/jR3BwuhaodwzRPmDyDQPmEMwornxrMLavTcC+Igb4k5qol0Di6Oq8axpBvrH7KlxHT11Wd+ALKCsqoPSGxcIbd6TdN+ag9AQIDAQAB"}`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.11 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/go.mod b/integrationTests/tests/go.mod new file mode 100644 index 0000000..02bc999 --- /dev/null +++ b/integrationTests/tests/go.mod @@ -0,0 +1,6 @@ +module securosys.ch/integration/tests + +replace securosys.ch/integration/client => ./../client +replace securosys.ch/test-helpers => ./../../testHelpers + +go 1.19 diff --git a/integrationTests/tests/go.sum b/integrationTests/tests/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/integration_junit_report.xml b/integration_junit_report.xml new file mode 100644 index 0000000..c834e42 --- /dev/null +++ b/integration_junit_report.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/junit_report.xml b/junit_report.xml new file mode 100644 index 0000000..8d5e7f5 --- /dev/null +++ b/junit_report.xml @@ -0,0 +1,297 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..ebd8a3d --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.0.3 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..0ace864 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/go.work b/tests/go.work new file mode 100644 index 0000000..7c33c4f --- /dev/null +++ b/tests/go.work @@ -0,0 +1,5 @@ +go 1.21 + +use ( + ./ +) \ No newline at end of file diff --git a/tests/go.work.sum b/tests/go.work.sum new file mode 100644 index 0000000..aff7933 --- /dev/null +++ b/tests/go.work.sum @@ -0,0 +1,163 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} diff --git a/tests/path_mariadb_integration_test.go b/tests/path_mariadb_integration_test.go new file mode 100644 index 0000000..fbbdc5a --- /dev/null +++ b/tests/path_mariadb_integration_test.go @@ -0,0 +1,78 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +// func TestIntegrationMariaDB(t *testing.T) { +// testEnv, err := testHelpers.NewTestEnv() +// if err != nil { +// t.Fatal(err) +// } +// t.Run("A) add config", testEnv.AddConfig) + +// t.Run("B) Test Creating RSA key", func(t *testing.T) { +// now := time.Now().UTC() +// timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) +// err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ +// "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, +// "keySize": 2048, +// "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, +// }, "custom_rsa_2048", "rsa") + +// assert.NoError(t, err) + +// }) +// t.Run("C)Add generate secret", func(t *testing.T) { +// _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ +// Operation: logical.CreateOperation, +// Path: "integrations/mariadb/test", +// Data: map[string]interface{}{ +// "keyName": "custom_rsa_2048", +// "cipherAlgorithm": "RSA", +// }, +// Storage: testEnv.Storage, +// }) + +// }) +// t.Run("D) Read secret", func(t *testing.T) { +// _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ +// Operation: logical.ReadOperation, +// Path: "integrations/mariadb/test/v1?key_name=custom_rsa_2048&cipher_algorithm=RSA", +// Data: map[string]interface{}{}, +// Storage: testEnv.Storage, +// }) + +// }) +// t.Run("E)Rotate secret", func(t *testing.T) { +// _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ +// Operation: logical.CreateOperation, +// Path: "integrations/mariadb/test", +// Data: map[string]interface{}{ +// "keyName": "custom_rsa_2048", +// "cipherAlgorithm": "RSA", +// }, +// Storage: testEnv.Storage, +// }) + +// }) +// t.Run("F) Test Delete RSA key", func(t *testing.T) { +// err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") +// assert.NoError(t, err) +// }) +// } From 69cb7163e20031741fa1a648ec71e483854ba9b0 Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Tue, 28 Nov 2023 15:02:58 +0100 Subject: [PATCH 04/16] Release v.1.0.3 --- .github/ISSUE_TEMPLATE/bug-report-sse.md | 49 + .github/ISSUE_TEMPLATE/feature-request-sse.md | 33 + .gitignore | 4 + LICENSE | 201 ++ Makefile | 165 + Readme.md | 983 ++++++ backend/backend.go | 139 + backend/go.mod | 62 + backend/go.sum | 223 ++ backend/path_config.go | 274 ++ backend/path_help.go | 425 +++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 ++ backend/path_hsm_key_bls.go | 259 ++ backend/path_hsm_key_camellia.go | 226 ++ backend/path_hsm_key_chacha20.go | 208 ++ backend/path_hsm_key_dsa.go | 273 ++ backend/path_hsm_key_ec.go | 270 ++ backend/path_hsm_key_ed.go | 271 ++ backend/path_hsm_key_import.go | 306 ++ backend/path_hsm_key_rsa.go | 273 ++ backend/path_hsm_key_tdea.go | 208 ++ backend/path_hsm_key_with_name.go | 295 ++ backend/path_hsm_keys.go | 1359 ++++++++ backend/path_hsm_operations.go | 1631 ++++++++++ backend/path_hsm_requests.go | 298 ++ client/client.go | 48 + client/client_tsb.go | 1011 ++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + etc/example/policy.json | 93 + etc/release_notes/Release_Notes.md | 20 + go.mod | 22 + go.sum | 2754 +++++++++++++++++ helpers/consts.go | 53 + helpers/functions.go | 191 ++ helpers/go.mod | 57 + helpers/go.sum | 223 ++ helpers/structs.go | 315 ++ project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 ++ testHelpers/test_client_tsb.go | 151 + testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 +++++ tests/go.mod | 66 + tests/go.sum | 223 ++ tests/path_config_test.go | 153 + tests/path_hsm_key_aes_test.go | 133 + tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 + tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 + tests/path_hsm_key_tdea_test.go | 136 + tests/path_hsm_key_using_type_name_test.go | 245 ++ tests/path_hsm_keys_rotation_test.go | 836 +++++ tests/path_hsm_keys_test.go | 312 ++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++ tests/path_hsm_operations_sign_test.go | 647 ++++ tests/path_hsm_operations_unwrap_test.go | 675 ++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++ tests/path_hsm_operations_wrap_test.go | 242 ++ tests/path_hsm_requests_test.go | 299 ++ 69 files changed, 22673 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-sse.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-sse.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/structs.go create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go diff --git a/.github/ISSUE_TEMPLATE/bug-report-sse.md b/.github/ISSUE_TEMPLATE/bug-report-sse.md new file mode 100644 index 0000000..40777e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-sse.md @@ -0,0 +1,49 @@ +--- +name: Bug report SSE +about: Create a report to help us improve +title: "[BUG] " +labels: '' +assignees: Peter-FNet + +--- + + + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment:** +* Vault Server Version (retrieve with `vault status`): +* Vault CLI Version (retrieve with `vault version`): +* Server Operating System/Architecture: + +Vault server configuration file(s): + +```hcl +# Paste your Vault config here. +# Be sure to scrub any sensitive values +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request-sse.md b/.github/ISSUE_TEMPLATE/feature-request-sse.md new file mode 100644 index 0000000..8264e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-sse.md @@ -0,0 +1,33 @@ +--- +name: Feature request SSE +about: Suggest an idea for this project +title: "[FEAT]" +labels: '' +assignees: Peter-FNet + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Explain any additional use-cases** +If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5375b60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +builds +vault +deploy +.gitlab-ci.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d1ed730 --- /dev/null +++ b/Makefile @@ -0,0 +1,165 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + echo "Finished!"; + + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 15m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..6a06f46 --- /dev/null +++ b/Readme.md @@ -0,0 +1,983 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Appendix +### Frequently Asked Questions + +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..92d0f39 --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,139 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..7dba7ce --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,274 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "io/ioutil" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := ioutil.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} + diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..a26e88a --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,425 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + + + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} \ No newline at end of file diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..dca8ab1 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} \ No newline at end of file diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..41d1aa7 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} \ No newline at end of file diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..3025b53 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1011 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + `+passwordString+` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + `+passwordString+` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString:=""; + if(len(keyToBeWrappedPasswordJson)>2){ + keyToBeWrappedPasswordString=`"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString:=""; + if(len(wrapKeyPasswordJson)>2){ + wrapKeyPasswordString=`"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + `+keyToBeWrappedPasswordString+` + "wrapKeyName": "` + wrapKeyName + `", + `+wrapKeyPasswordString+` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + `+passwordString+` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + `+passwordString+` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + `+passwordString+` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + `+passwordString+` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + `+passwordString+` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + `+passwordString+` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + `+passwordString+` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + `+passwordString+` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + `+passwordString+` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + `+passwordString+` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + `+passwordString+` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + `+passwordString+` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString:=""; + if(len(charsNewPasswordJson)>2){ + newPasswordString=`"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + `+passwordString+newPasswordString+` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + `+passwordString+` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + `+passwordString+` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + `+passwordString+` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..8e00e02 --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,93 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..8aa2a7e --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,20 @@ +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d7aecd8 --- /dev/null +++ b/go.mod @@ -0,0 +1,22 @@ +module secretengine + +go 1.16 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers +replace securosys.ch/tests => ./tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8938e00 --- /dev/null +++ b/go.sum @@ -0,0 +1,2754 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20221206110420-d395f97c4830/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= +github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20221215162035-5330a85ea652/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v56.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= +github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= +github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= +github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= +github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.9.3/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.9.4/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.9.6/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.10.0-rc.7/go.mod h1:ILuwjA+kNW+MrN/w5un7n3mTqkwsFu4Bp05/okFUZlE= +github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= +github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk= +github.com/alexflint/go-filemutex v1.2.0/go.mod h1:mYyQSWvw9Tx2/H2n9qXPb52tTYfE0pZAWcBq5mK025c= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220418222510-f25a4f6275ed/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.43.16/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/bytecodealliance/wasmtime-go v0.36.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI= +github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/container-orchestrated-devices/container-device-interface v0.5.4/go.mod h1:DjE95rfPiiSmG7uVXtg0z6MnPm/Lx4wxKCIts0ZE0vg= +github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= +github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= +github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= +github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/btrfs/v2 v2.0.0/go.mod h1:swkD/7j9HApWpzl8OHfrHNxppPd9l44DFZdF94BUj9k= +github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/containerd/cgroups/v3 v3.0.1/go.mod h1:/vtwk1VXrtoa5AaZLkypuOJgA/6DyPMZHJPGQNtlHnw= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= +github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= +github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= +github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= +github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= +github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= +github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s= +github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE= +github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0= +github.com/containerd/containerd v1.6.8/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0= +github.com/containerd/containerd v1.6.9/go.mod h1:XVicUvkxOrftE2Q1YWUXgZwkkAxwQYNOFzYWvfVfEfQ= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= +github.com/containerd/continuity v0.2.2/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= +github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= +github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk= +github.com/containerd/go-cni v1.1.0/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA= +github.com/containerd/go-cni v1.1.3/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA= +github.com/containerd/go-cni v1.1.6/go.mod h1:BWtoWl5ghVymxu6MBjg79W9NZrCRyHIdUtk4cauMe34= +github.com/containerd/go-cni v1.1.9/go.mod h1:XYrZJ1d5W6E2VOvjffL3IZq0Dz6bsVlERHbekNK90PM= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= +github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= +github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow= +github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms= +github.com/containerd/imgcrypt v1.1.3/go.mod h1:/TPA1GIDXMzbj01yd8pIbQiLdQxed5ue1wb8bP7PQu4= +github.com/containerd/imgcrypt v1.1.4/go.mod h1:LorQnPtzL/T0IyCeftcsMEO7AqxUDbdO8j/tSUpgxvo= +github.com/containerd/imgcrypt v1.1.7/go.mod h1:FD8gqIcX5aTotCtOmjeCsi3A1dHmTZpnMISGKSczt4k= +github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= +github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/nri v0.3.0/go.mod h1:Zw9q2lP16sdg0zYybemZ9yTDy8g7fPCIB3KXOGlggXI= +github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM= +github.com/containerd/stargz-snapshotter/estargz v0.12.1/go.mod h1:12VUuCq3qPq4y8yUW+l5w3+oXV3cx2Po3KSe/SmPGqw= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= +github.com/containerd/ttrpc v1.1.1-0.20220420014843-944ef4a40df3/go.mod h1:YYyNVhZrTMiaf51Vj6WhAJqJw+vl/nzABhj8pWrzle4= +github.com/containerd/ttrpc v1.2.1/go.mod h1:sIT6l32Ph/H9cvnJsfXM5drIVzTr5A2flTf1G5tYZak= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containerd/typeurl/v2 v2.1.0/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= +github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= +github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= +github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y= +github.com/containernetworking/cni v1.1.1/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= +github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= +github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= +github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= +github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNBDZcxSOplJT5ico8/FLE= +github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8= +github.com/containernetworking/plugins v1.2.0/go.mod h1:/VjX4uHecW5vVimFa1wkG4s+r/s9qIfPdqlLF4TW8c4= +github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= +github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= +github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/containers/ocicrypt v1.1.3/go.mod h1:xpdkbVAuaH3WzbEabUd5yDsl9SwJA5pABH85425Es2g= +github.com/containers/ocicrypt v1.1.6/go.mod h1:WgjxPWdTJMqYMjf3M6cuIFFA1/MpyyhIM99YInA+Rvc= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= +github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= +github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M= +github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/distribution/distribution/v3 v3.0.0-20220526142353-ffbd94cbe269/go.mod h1:28YO/VJk9/64+sTGNuYaBjWxrXTPrj0C0XmgTIOjxX4= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.20+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.20+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= +github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/foxcpp/go-mockdns v0.0.0-20210729171921-fb145fc6f897/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-ini/ini v1.66.6/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/cel-go v0.12.6/go.mod h1:Jk7ljRzLBhkmiAwBoUxB1sZSCVBAzkqPF25olK/iRDw= +github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= +github.com/google/go-containerregistry v0.13.0/go.mod h1:J9FQ+eSS4a1aC2GNZxvNpbWhgp0487v+cgiilB4FqDo= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= +github.com/intel/goresctrl v0.3.0/go.mod h1:fdz3mD85cmP9sHD8JUlrNWAxvwM86CrbmVXltEKd7zk= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= +github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= +github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= +github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= +github.com/lestrrat-go/jwx v1.2.25/go.mod h1:zoNuZymNl5lgdcu6P7K6ie2QRll5HVfF4xwxBBK1NxY= +github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= +github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= +github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/networkplumbing/go-nft v0.2.0/go.mod h1:HnnM+tYvlGAsMU7yoYwXEVLLiDW9gdMmb5HoGcwpuQs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= +github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= +github.com/onsi/ginkgo/v2 v2.6.1/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= +github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= +github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= +github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= +github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk= +github.com/open-policy-agent/opa v0.42.2/go.mod h1:MrmoTi/BsKWT58kXlVayBb+rYVeaMwuBm3nYAN3923s= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runc v1.1.4/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.1.0-rc.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626/go.mod h1:BRHJJd0E+cx42OybVYSgUvZmU0B8P9gZuRXlZUP7TKI= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/peterh/liner v0.0.0-20170211195444-bf27d3ba8e1d/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/safchain/ethtool v0.2.0/go.mod h1:WkKB1DnNtvsMlDmQ50sgwowDJV/hGbJSOvJoEXs1AJQ= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.19.1/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= +github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= +github.com/vektah/gqlparser/v2 v2.4.5/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0= +github.com/veraison/go-cose v1.0.0-rc.1/go.mod h1:7ziE85vSq4ScFTg6wyoMXjucIGOf4JkFEZi/an96Ct4= +github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yashtewari/glob-intersection v0.1.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.5/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v2 v2.305.5/go.mod h1:zQjKllfqfBVyVStbt4FaosoX2iYd8fV/GRy/PbowgP4= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/client/v3 v3.5.5/go.mod h1:aApjR4WGlSumpnJ2kloS75h6aHUmAyaPLjHMxpc7E7c= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/pkg/v3 v3.5.5/go.mod h1:6ksYFxttiUGzC2uxyqiyOEvhAiD0tuIqSZkX3TyPdaE= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/raft/v3 v3.5.5/go.mod h1:76TA48q03g1y1VpTue92jZLr9lIHKUNcYdZOOGyx8rI= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= +go.etcd.io/etcd/server/v3 v3.5.5/go.mod h1:rZ95vDw/jrvsbj9XpTqPrTAB9/kzchVdhRirySPkUBc= +go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0/go.mod h1:h8TWwRAhQpOd0aM5nYsRD8+flnkj+526GEIVlarH7eY= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0/go.mod h1:UMklln0+MRhZC4e3PwmN3pCtq4DyIadWw4yikh6bNrw= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0/go.mod h1:5eCOqeGphOyz6TsY3ZDNjE33SM/TFAK3RGuCL2naTgY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.35.0/go.mod h1:9NiG9I2aHTKkcxqCILhjtyNA1QEiCjdBACv4IvrFQ+c= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU= +go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= +go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= +go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM= +go.opentelemetry.io/otel v1.10.0/go.mod h1:NbvWjCthWHKBEUMpf0/v8ZRZlni86PpGFEMA9pnQSnQ= +go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0/go.mod h1:M1hVZHNxcbkAlcvrOMlpQ4YOO3Awf+4N2dxkZL3xm04= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0/go.mod h1:78XhIg8Ht9vR4tbLNUhXsiOnE2HOuSeKAiAcoVQEpOY= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0/go.mod h1:UFG7EBMRdXyFstOwH028U0sVf+AvukSGhF0g8+dmNG8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0/go.mod h1:ceUgdyfNv4h4gLxHR0WNfDiiVmZFodZhZSbOLhpxqXE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.10.0/go.mod h1:Krqnjl22jUJ0HgMzw5eveuCvFDXY4nSYb4F8t5gdrag= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0/go.mod h1:HrbCVv40OOLTABmOn1ZWty6CHXkU8DK/Urc43tHug70= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0/go.mod h1:E+/KKhwOSw8yoPxSSuUHG6vKppkvhN+S1Jc7Nib3k3o= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.10.0/go.mod h1:OfUCyyIiDvNXHWpcWgbF+MWvqPZiNa3YDEnivcnYsV0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0/go.mod h1:5w41DY6S9gZrbjuq6Y+753e96WfPha5IcsOSZTtullM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0/go.mod h1:+N7zNjIJv4K+DeX67XXET0P+eIciESgaFDBqh+ZJFS4= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/metric v0.30.0/go.mod h1:/ShZ7+TS4dHzDFmfi1kSXMhMVubNoP0oIaBp70J6UXU= +go.opentelemetry.io/otel/metric v0.31.0/go.mod h1:ohmwj9KTSIeBnDBm/ZwH2PSZxZzoOaG2xZeekTRzL5A= +go.opentelemetry.io/otel/metric v0.37.0/go.mod h1:DmdaHfGt54iV6UKxsV9slj2bBRJcKC1B1uvDLIioc1s= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI= +go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= +go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU= +go.opentelemetry.io/otel/sdk v1.10.0/go.mod h1:vO06iKzD5baltJz1zarxMCNHFpUlUiOy4s65ECtn6kE= +go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk= +go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk= +go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= +go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4= +go.opentelemetry.io/otel/trace v1.10.0/go.mod h1:Sij3YYczqAdz+EhmGhE6TpTxUO5/F/AzrK+kxfGqySM= +go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg= +go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220405210540-1e041c57c461/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= +k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= +k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= +k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= +k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= +k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= +k8s.io/apimachinery v0.25.0/go.mod h1:qMx9eAk0sZQGsXGu86fab8tZdffHbwUfsvzqKn4mfB0= +k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= +k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= +k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ= +k8s.io/apiserver v0.26.2/go.mod h1:GHcozwXgXsPuOJ28EnQ/jXEM9QeG6HT22YxSNmpYNh8= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= +k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= +k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= +k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= +k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= +k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= +k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI= +k8s.io/component-base v0.26.2/go.mod h1:DxbuIe9M3IZPRxPIzhch2m1eT7uFrSBJUBuVCQEBivs= +k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= +k8s.io/cri-api v0.23.1/go.mod h1:REJE3PSU0h/LOV1APBrupxrEJqnoxZC8KWzkBUHwrK4= +k8s.io/cri-api v0.25.0/go.mod h1:J1rAyQkSJ2Q6I+aBMOVgg2/cbbebso6FNa0UagiR0kc= +k8s.io/cri-api v0.25.3/go.mod h1:riC/P0yOGUf2K1735wW+CXs1aY2ctBgePtnnoFLd0dU= +k8s.io/cri-api v0.26.2/go.mod h1:Oo8O7MKFPNDxfDf2LmrF/3Hf30q1C6iliGuv3la3tIA= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kms v0.26.2/go.mod h1:69qGnf1NsFOQP07fBYqNLZklqEHSJF024JqYCaeVxHg= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= +modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= +oras.land/oras-go v1.2.0/go.mod h1:pFNs7oHp2dYsYMSS82HaX5l4mpnGO7hbpPN6EWH2ltc= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.35/go.mod h1:WxjusMwXlKzfAs4p9km6XJRndVt2FROgMVCE4cdohFo= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..1925e0e --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,191 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9249056 --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,315 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..ebd8a3d --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.0.3 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..b55e030 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_API_URL", + "auth": "TOKEN", + "bearertoken": "TSB_BEARER_TOKEN", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} From 6875381bdac00c61cd0cbb53c6f477eb33fd8879 Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Mon, 15 Jan 2024 11:05:06 +0100 Subject: [PATCH 05/16] Release v.1.0.3 --- .gitignore | 7 + LICENSE.txt | 201 ++ Makefile | 201 ++ Readme.md | 1145 ++++++++++++ backend/backend.go | 140 ++ backend/go.mod | 62 + backend/go.sum | 223 +++ backend/path_config.go | 294 +++ backend/path_help.go | 452 +++++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 +++ backend/path_hsm_key_bls.go | 259 +++ backend/path_hsm_key_camellia.go | 225 +++ backend/path_hsm_key_chacha20.go | 208 +++ backend/path_hsm_key_dsa.go | 273 +++ backend/path_hsm_key_ec.go | 270 +++ backend/path_hsm_key_ed.go | 271 +++ backend/path_hsm_key_import.go | 306 ++++ backend/path_hsm_key_rsa.go | 273 +++ backend/path_hsm_key_tdea.go | 208 +++ backend/path_hsm_key_with_name.go | 295 +++ backend/path_hsm_keys.go | 1359 ++++++++++++++ backend/path_hsm_operations.go | 1631 +++++++++++++++++ backend/path_hsm_requests.go | 298 +++ backend/path_mariadb_integration.go | 666 +++++++ client/client.go | 48 + client/client_tsb.go | 1023 +++++++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + .../alpine3/docker-compose-alpine3.yml | 56 + docker-builder/build-in-docker.sh | 12 + etc/example/mariaDb.cfg | 22 + etc/example/policy.json | 97 + etc/release_notes/Release_Notes.md | 29 + go.mod | 80 + go.sum | 254 +++ go.work | 8 + go.work.sum | 164 ++ helpers/consts.go | 53 + helpers/functions.go | 234 +++ helpers/go.mod | 57 + helpers/go.sum | 223 +++ helpers/mariadb_structs.go | 82 + helpers/structs.go | 316 ++++ integrationTests/client/client.go | 30 + integrationTests/client/client_config.go | 15 + integrationTests/client/go.mod | 24 + integrationTests/client/go.sum | 58 + integrationTests/docker/docker-compose.yml | 39 + .../docker/docker-files/MariaDB_Dockerfile | 2 + .../docker/mysql-config/hashicorp.cnf | 18 + .../tests/a_enable_plugin_test.go | 48 + .../tests/b_config_plugin_test.go | 55 + .../tests/c_create_aes_key_test.go | 234 +++ .../tests/c_create_key_by_keyname_test.go | 93 + .../tests/c_create_rsa_key_test.go | 250 +++ .../tests/c_create_smart_rsa_key_test.go | 255 +++ .../tests/d_operations_on_key_test.go | 329 ++++ integrationTests/tests/go.mod | 6 + integrationTests/tests/go.sum | 0 junit_report.xml | 0 project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 +++ testHelpers/test_client_tsb.go | 151 ++ testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 ++++++++ tests/go.mod | 66 + tests/go.sum | 223 +++ tests/go.work | 5 + tests/go.work.sum | 163 ++ tests/path_config_test.go | 153 ++ tests/path_hsm_key_aes_test.go | 133 ++ tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 ++ tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 ++ tests/path_hsm_key_tdea_test.go | 136 ++ tests/path_hsm_key_using_type_name_test.go | 245 +++ tests/path_hsm_keys_rotation_test.go | 836 +++++++++ tests/path_hsm_keys_test.go | 312 ++++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++++ tests/path_hsm_operations_sign_test.go | 647 +++++++ tests/path_hsm_operations_unwrap_test.go | 675 +++++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++++++++ tests/path_hsm_operations_wrap_test.go | 242 +++ tests/path_hsm_requests_test.go | 299 +++ tests/path_mariadb_integration_test.go | 111 ++ 94 files changed, 23211 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.txt create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 backend/path_mariadb_integration.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 docker-builder/alpine3/docker-compose-alpine3.yml create mode 100644 docker-builder/build-in-docker.sh create mode 100644 etc/example/mariaDb.cfg create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 go.work create mode 100644 go.work.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/mariadb_structs.go create mode 100644 helpers/structs.go create mode 100644 integrationTests/client/client.go create mode 100644 integrationTests/client/client_config.go create mode 100644 integrationTests/client/go.mod create mode 100644 integrationTests/client/go.sum create mode 100644 integrationTests/docker/docker-compose.yml create mode 100644 integrationTests/docker/docker-files/MariaDB_Dockerfile create mode 100644 integrationTests/docker/mysql-config/hashicorp.cnf create mode 100644 integrationTests/tests/a_enable_plugin_test.go create mode 100644 integrationTests/tests/b_config_plugin_test.go create mode 100644 integrationTests/tests/c_create_aes_key_test.go create mode 100644 integrationTests/tests/c_create_key_by_keyname_test.go create mode 100644 integrationTests/tests/c_create_rsa_key_test.go create mode 100644 integrationTests/tests/c_create_smart_rsa_key_test.go create mode 100644 integrationTests/tests/d_operations_on_key_test.go create mode 100644 integrationTests/tests/go.mod create mode 100644 integrationTests/tests/go.sum create mode 100644 junit_report.xml create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/go.work create mode 100644 tests/go.work.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go create mode 100644 tests/path_mariadb_integration_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3badb78 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +builds +test + +vault_exec + +deploy +.gitlab-ci.yml diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6c1dbba --- /dev/null +++ b/Makefile @@ -0,0 +1,201 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` + +ifndef ARTIFACT_NAME +override ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +endif + +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + make release-alpine3 + echo "Finished!"; + +release-alpine3: + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-amd64 + make clean-docker-builder IMAGE=amd64/golang + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-i386 + make clean-docker-builder IMAGE=i386/golang + +clean-docker-builder: + @if [ "$$(docker images | grep '$(IMAGE)')" != "" ]; then \ + docker rmi -f $$(docker images | grep '$(IMAGE)' | awk '{ print $$3}') 2> /dev/null || true ; \ + fi; + docker volume prune -f + docker container prune -f + +run-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml up --build -d +clean-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml down --remove-orphans --rmi all + docker volume prune -f + docker container prune -f + + + +integration-tests: + rm -fr integrationTests/docker/plugins/securosys-hsm + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -o integrationTests/docker/plugins/securosys-hsm cmd/securosys-hsm/main.go + make run-docker-test-container + + sleep 5 + go install github.com/jstemmer/go-junit-report/v2@latest + cd integrationTests/tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}integration_junit_report.xml -set-exit-code + + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4828e0e --- /dev/null +++ b/Readme.md @@ -0,0 +1,1145 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Integrations](#integrations) + - [MariaDB](#mariadb) + - [Example usage](#mariadb-usage-example) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate and `keypath` with local PATH to the key. +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for Certificate authorization**: +```shell +$ vault write securosys-hsm/config +auth="CERT" +certpath="local_absolute_path_to_certificate.pem" +keypath="local_absolute_path_to_private.key" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=CERT' \ +--data-urlencode 'certpath=local_absolute_path_to_certificate.pem' \ +--data-urlencode 'keypath=local_absolute_path_to_private.pem' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Integrations +### MariaDB +Encryption on MariaDB can be enabled using existing plugin [Hashicorp Key Management Plugin](https://mariadb.com/kb/en/hashicorp-key-management-plugin/) +This integration stores generated secret in Secrets engine, encrypted by provided key. +**Supported Key Types**/**Algorithm** combinations: +| Key Type | Algorithm | +|----------|:-------------:| +| **RSA** |RSA_PADDING_OAEP_WITH_SHA512
RSA
RSA_PADDING_OAEP_WITH_SHA224
RSA_PADDING_OAEP_WITH_SHA256
RSA_PADDING_OAEP_WITH_SHA1
RSA_PADDING_OAEP
RSA_PADDING_OAEP_WITH_SHA384
RSA_NO_PADDING| +|**AES**|AES_GCM
AES_CTR
AES_ECB
AES_CBC_NO_PADDING
AES | +| **CHACHA20** | CHACHA20
CHACHA20_AEAD| +| **CAMELLIA** | CAMELLIA
CAMELLIA_CBC_NO_PADDING
CAMELLIA_ECB | +|**TDEA**| TDEA_CBC
TDEA_ECB
TDEA_CBC_NO_PADDING | + +>**Note** - Plugin supports **asynchronous decrypt operation** using key type **RSA** with **policy** with setup **ruleUse**. Using the key with policy will **stop** the decrypt operation and **wait for approvals** to be collected. + +There are a **serval steps** that is needed to be done before setup encryption on MariaDB +1) [Create / Register key](#manage-keys) into **Secrets Engine** +1) Generate new **secret** and encrypt it using stored key + ```shell + $ vault write securosys-hsm/integrations/mariadb/{secret-name} + keyName={key-name-from-secret-engine} + cipherAlgorithm={cipher-algorithm} + [additionalAuthenticationData={additional-authentication-data}] + [tagLength={tag-length}] + [password={password-for-a-key}] + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/integrations/mariadb/{secret-name} ' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName={key-name-from-secret-engine}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + >**Note** - Every request on this endpoint using same **key name** and **secret name** will **rotate secret** +1) The last step is add this configuration to **my.cfg** + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" + loose-hashicorp-key-management-token="{vault_access_token}" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + >**Note** - In **loose-hashicorp-key-management-vault-url** url need to ends with **&version=**. Plugin from **MariaDB** automatically add to end of url **number of secret version** +#### MariaDB usage example +This example using default configuration for **Hashicorp Vault dev server**. +| Data | Value | +|----------|:-------------:| +| **vault address** | https://localhost:8200 | +| **vault access token** | root | +1) **Create key** *MariaDBEncryptionKey* with key size *4096* with attributes at last "decrypt" equals *true* on HSM and store it as *mariadb_encryption_key* on **Secrets engine** + ```shell + $ vault write securosys-hsm/keys/rsa/mariadb_encryption_key + keyLabel="MariaDBEncryptionKey" + keySize=4096 + attributes='{"decrypt": true,"sign": false,"unwrap": false,"derive": true,"sensitive": true,"extractable": false,"modifiable": false,"copyable": false,"destroyable": true}' + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/keys/rsa/mariadb_encryption_key' \ + --header 'X-Vault-Token: root' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel=MariaDBEncryptionKey' \ + --data-urlencode 'keySize=4096' \ + --data-urlencode 'attributes={ + "decrypt": true, + "sign": false, + "unwrap": false, + "derive": true, + "sensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": false, + "copyable": false, + "destroyable": true + }' + ``` +1) Generate new **secret** called *mariadb_secret* and **encrypt it** using cipher algorithm *RSA* and stored key *mariadb_encryption_key* in **Secrets engine** + ```shell + $ vault write securosys-hsm/integrations/mariadb/mariadb_secret + keyName=mariadb_encryption_key + cipherAlgorithm=RSA + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret ' \ + --header 'X-Vault-Token: root' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName=mariadb_encryption_key' \ + --data-urlencode 'cipherAlgorithm=RSA' + ``` +3. Configure **MariaDB plugin** "Hashicorp Key Management" in database configuration in **my.cnf** + + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret/?key_name=mariadb_encryption_key&cipher_algorithm=RSA&version=" + loose-hashicorp-key-management-token="root" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + + + +--- +## Appendix +### Frequently Asked Questions +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..67cf38a --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,140 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + pathMariaDBIntegration(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..29a1fac --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,294 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "keypath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to key", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "KeyPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if keypath, ok := data.GetOk("keypath"); ok { + config.KeyPath = keypath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing keypath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.KeyPath) + + if err != nil { + return nil, fmt.Errorf("Keypath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..8281fe0 --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,452 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..32954d9 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string), map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy, map[string]string{}) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil, map[string]string{}) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString, nil) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..e24fe58 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} diff --git a/backend/path_mariadb_integration.go b/backend/path_mariadb_integration.go new file mode 100644 index 0000000..0101c1d --- /dev/null +++ b/backend/path_mariadb_integration.go @@ -0,0 +1,666 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for create Camellia Keys +func pathMariaDBIntegration(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "keyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsDelete, + }, + }, + HelpSynopsis: pathIntegrationMariaDBWriteHelpSynopsis, + HelpDescription: pathIntegrationMariaDBWriteHelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("version") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV1HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV1HelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV2HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV2HelpDescription, + }, + { + Pattern: "integrations/mariadb/?$", + Fields: map[string]*framework.FieldSchema{}, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsList, + }, + }, + HelpSynopsis: pathIntegrationMariaDBListHelpSynopsis, + HelpDescription: pathIntegrationMariaDBListHelpDescription, + }, + } +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "intergration/mariadb/") + if err != nil { + return nil, err + } + secrets := make([]string, 0, len(entries)) + secretsInfo := make(map[string]interface{}) + for _, name := range entries { + secrets = append(secrets, name) + secret, err := b.GetMariaDBSecret(ctx, req.Storage, name) + if err == nil { + secretsInfo[name] = map[string]interface{}{ + "KeyName": secret.KeyName, + "Version": secret.CurrentVersion, + "Created": secret.Created.Name, + "Updated": secret.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(secrets, secretsInfo), nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, errGet := b.GetMariaDBSecret(ctx, req.Storage, name) + if errGet != nil { + return nil, fmt.Errorf("error deleting mariadb secret: %w", errGet) + } + if storedSecret == nil { + return nil, fmt.Errorf("error deleting mariadb secret: secret with name %s not exists", d.Get("name").(string)) + + } + + err := req.Storage.Delete(ctx, "intergration/mariadb/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + rotate := false + if storedSecret != nil { + rotate = true + // return nil, fmt.Errorf("error secret with name: %s exists", name) + } else { + storedSecret = &helpers.MariaDBSecretEntry{} + + } + + keyName := d.Get("keyName").(string) + + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload := b64.StdEncoding.EncodeToString([]byte(helpers.GeneratePassword(32, false, false, false, true))) + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + sysView := b.System() + creator := helpers.Entity{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + creator.Aliases = entity.Aliases + creator.Id = entity.ID + creator.Name = entity.Name + creator.Date = time.Now().UTC() + + } else { + creator.Aliases = nil + creator.Id = "root" + creator.Name = "root" + creator.Date = time.Now().UTC() + + } + var messageAuthenticationCode *string = nil + if result["messageAuthenticationCode"] != nil { + temp := result["messageAuthenticationCode"].(string) + messageAuthenticationCode = &temp + } + var initializationVector *string = nil + if result["initializationVector"] != nil { + temp := result["initializationVector"].(string) + initializationVector = &temp + } + if !rotate { + storedSecret.InitSecret(keyName, keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + } else { + storedSecret.RotateSecret(keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + + } + if err := SetMariaDBSecret(ctx, req.Storage, name, storedSecret); err != nil { + return nil, err + } + + response := map[string]interface{}{} + now := storedSecret.GetActiveVersion().Created.Date + version := storedSecret.GetActiveVersion().Version + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + query := d.Get("query").(string) + if strings.HasPrefix(query, "?") { + query = query[1:] + } + params, err := url.ParseQuery(query) + + if query == "" { + str := "" + for key, value := range req.Data { + str = str + key + "=" + value.(string) + "&" + } + str = str[:len(str)-1] + params, err = url.ParseQuery(str) + } + + if err != nil { + return nil, err + } + name := d.Get("name").(string) + + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + if storedSecret == nil { + return nil, fmt.Errorf("error secret with name: %s not exists", name) + } + + version := "1" + if params.Has("version") { + if !strings.Contains(params.Get("version"), "?version=") { + version = storedSecret.CurrentVersion + } else { + parts := strings.Split(params.Get("version"), "?version=") + version = "v" + parts[1] + } + } else { + ver, ok := d.GetOk("version") + if !ok { + return nil, fmt.Errorf("error: missing version") + } + version = ver.(string) + } + + if !params.Has("key_name") { + return nil, fmt.Errorf("key_name query param not exists") + } + keyEntry, err := b.GetKey(ctx, req.Storage, params.Get("key_name")) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + keyName := params.Get("key_name") + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + + if !helpers.ContainsKey(storedSecret.Versions, version) { + return nil, fmt.Errorf("Secret version %s is not exists.", version) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload := storedSecret.GetVersion(version).EncryptedSecret + + if !params.Has("cipher_algorithm") { + return nil, fmt.Errorf("cipher_algorithm query param not exists") + } + + cipherAlgorithm := params.Get("cipher_algorithm") + if keyEntry.KeyTypeName != "aes256-gcm96" && cipherAlgorithm == "" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVectorString := "" + if params.Has("initialization_vector") { + initializationVectorString = params.Get("initialization_vector") + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + passwordString := "" + if params.Has("password") { + passwordString = params.Get("password") + } + tagLengthInt := -1 + if params.Has("tag_length") { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + } + if keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationDataString := "" + if params.Has("aad") { + additionalAuthenticationDataString = params.Get("aad") + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationDataString) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData (param aad) is not valid base64 string") + } + } + client, err := b.GetClient(ctx, req.Storage) + async := false + decrypted := "" + if len(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + async = true + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString, map[string]string{"integration": "MariaDB Encrypt"}) + if errEnc != nil { + return nil, errEnc + } + var resp *helpers.RequestResponse + resp, _, _ = client.GetRequest(requestId) + for resp.Status == "PENDING" { + time.Sleep(1000) + resp, _, _ = client.GetRequest(requestId) + } + if resp.Status != "EXECUTED" { + return nil, fmt.Errorf("error on async decrypt. Expected Status '%s' got '%s'", "EXECUTED", resp.Status) + } + decrypted = resp.Result + + } + } + } + if !async { + resultSync, errEnc := client.Decrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + decrypted = resultSync["payload"].(string) + } + + if cipherAlgorithm == "AES_ECB" || + cipherAlgorithm == "AES_CBC_NO_PADDING" || + cipherAlgorithm == "CAMELLIA_ECB" || + cipherAlgorithm == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + decoded, _ := base64.StdEncoding.DecodeString(decrypted) + response := map[string]interface{}{} + response["data"] = map[string]interface{}{"data": string(decoded)} + now := storedSecret.GetVersion(version).Created.Date + + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} + +// This function helps with saving key in Secrets Engine +func SetMariaDBSecret(ctx context.Context, s logical.Storage, name string, secretEntry *helpers.MariaDBSecretEntry) error { + entry, err := logical.StorageEntryJSON("intergration/mariadb/"+name, secretEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage secret") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetMariaDBSecret(ctx context.Context, s logical.Storage, name string) (*helpers.MariaDBSecretEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "intergration/mariadb/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var secret helpers.MariaDBSecretEntry + + if err := entry.DecodeJSON(&secret); err != nil { + return nil, err + } + return &secret, nil +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..b50c7e2 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1023 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + KeyPath: data["keypath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + ` + passwordString + ` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy, customMetaData map[string]string) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo, customMetaData) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString := "" + if len(keyToBeWrappedPasswordJson) > 2 { + keyToBeWrappedPasswordString = `"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString := "" + if len(wrapKeyPasswordJson) > 2 { + wrapKeyPasswordString = `"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + ` + keyToBeWrappedPasswordString + ` + "wrapKeyName": "` + wrapKeyName + `", + ` + wrapKeyPasswordString + ` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + ` + passwordString + ` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + ` + passwordString + ` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + ` + passwordString + ` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + ` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString := "" + if len(charsNewPasswordJson) > 2 { + newPasswordString = `"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + newPasswordString + ` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + passwordString + ` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + clientTLSCert, err := tls.LoadX509KeyPair(c.Auth.CertPath, c.Auth.KeyPath) + if err != nil { + log.Fatalf("Error loading certificate and key file: %v", err) + return nil, err, 0 + } + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + InsecureSkipVerify: true, + Certificates: []tls.Certificate{clientTLSCert}, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/docker-builder/alpine3/docker-compose-alpine3.yml b/docker-builder/alpine3/docker-compose-alpine3.yml new file mode 100644 index 0000000..1190d88 --- /dev/null +++ b/docker-builder/alpine3/docker-compose-alpine3.yml @@ -0,0 +1,56 @@ + version: "3.3" + services: + golang-builder-alpine3-amd64: + platform: linux/amd64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=amd64 + image: amd64/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-amd64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-i386: + platform: linux/i386 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=386 + image: i386/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-i386 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-arm64: + platform: linux/arm64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=arm64 + image: arm64v8/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-arm64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" \ No newline at end of file diff --git a/docker-builder/build-in-docker.sh b/docker-builder/build-in-docker.sh new file mode 100644 index 0000000..adc15b2 --- /dev/null +++ b/docker-builder/build-in-docker.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd .. +echo "Build ${ARTIFACT_NAME} in ${DOCKER_OS}_${DOCKER_ARCH}"; + cd /src + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; + cd builds; + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; + zip -9 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; + shasum -a 256 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; + cd ..; + rm builds/securosys-hsm; + rm builds/securosys-hsm_SHA256SUM; \ No newline at end of file diff --git a/etc/example/mariaDb.cfg b/etc/example/mariaDb.cfg new file mode 100644 index 0000000..298e73a --- /dev/null +++ b/etc/example/mariaDb.cfg @@ -0,0 +1,22 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" +loose-hashicorp-key-management-token="{vault_access_token}" +loose-hashicorp-key-management-check-kv-version="off" +#max timeout is 86400 seconds +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +#1 year in miliseconds +loose-hashicorp-key-management-cache-timeout=31556952000 +#1 year in miliseconds +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +#Example of innodb config +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = ON +innodb_encrypt_log = ON +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 \ No newline at end of file diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..102a86b --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,97 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value": +"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value": + "replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value": + "replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "TM", + "value": +"replace_me_with_approval_key/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..6eebb05 --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,29 @@ +# Securosys Hashicorp Vault Secrets Engine 1.1.0 +Issued: Dec, 6, 2023 +## Documentation Change +- Update Readme.md - added information about supporting and how to configure encryption on MariaDB +## Feature +- Added integration with MariaDB encryption +## Bugfix +- Fixed authentication with TSB using mTLS + +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build/ + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2d78c0c --- /dev/null +++ b/go.mod @@ -0,0 +1,80 @@ +module secretengine + +go 1.21 + +toolchain go1.21.2 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers + +replace securosys.ch/tests => ./tests + +replace securosys.ch/integration/client => ./integrationTests/client + +replace securosys.ch/integration/tests => ./integrationTests/tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/frankban/quicktest v1.14.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afae25d --- /dev/null +++ b/go.sum @@ -0,0 +1,254 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work new file mode 100644 index 0000000..ad36518 --- /dev/null +++ b/go.work @@ -0,0 +1,8 @@ +go 1.21 + +use ( + ./ + ./backend + ./integrationTests/client + ./integrationTests/tests +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..976ca94 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,164 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..bdc47e4 --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "math/rand" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} +func GetVersionNumber(version string) int { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + return versionInt +} +func GetVersionString(version string) string { + return strings.Replace(version, "v", "", 1) +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string, customMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + for key, value := range customMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + specialBytes = "!@#$%^&*()_+-=[]{}\\|;':\",.<>/?`~" + numBytes = "0123456789" + hexDecimalBytes = "0123456789ABCDEF" +) + +func GeneratePassword(length int, useLetters bool, useSpecial bool, useNum bool, useHexadecimal bool) string { + rand.Seed(time.Now().UnixNano()) + b := make([]byte, length) + arrayForRandom := make([]byte, 0) + if useLetters { + arrayForRandom = append(arrayForRandom, letterBytes...) + } + if useSpecial { + arrayForRandom = append(arrayForRandom, specialBytes...) + } + if useNum { + arrayForRandom = append(arrayForRandom, numBytes...) + } + if useHexadecimal { + arrayForRandom = append(arrayForRandom, hexDecimalBytes...) + + } + + for i := range b { + b[i] = arrayForRandom[rand.Intn(len(arrayForRandom))] + } + return string(b) +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/mariadb_structs.go b/helpers/mariadb_structs.go new file mode 100644 index 0000000..97210ac --- /dev/null +++ b/helpers/mariadb_structs.go @@ -0,0 +1,82 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// INTEGRATION MARIADB STRUCTS + +type MariaDBSecretEntry struct { + KeyName string `json:"keyName"` + Versions map[string]MariaDBSecretVersion `json:"secretVersions"` + CurrentVersion string `json:"defaultVersion"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +// Struct of keys stored inside the Vault +type MariaDBSecretVersion struct { + KeyVersion string `json:"keyVersion"` + EncryptedSecret string `json:"encryptedSecret"` + MessageAuthenticationCode *string `json:"messageAuthenticationCode"` + InitializationVector *string `json:"initializationVector"` + Version string `json:"version"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (s *MariaDBSecretEntry) InitSecret(keyName string, keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, creator Entity) { + s.CurrentVersion = "v1" + s.KeyName = keyName + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = "v1" + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = creator + secretVersion.Updated = creator + s.Created = creator + s.Updated = creator + s.Versions = make(map[string]MariaDBSecretVersion) + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) RotateSecret(keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, updater Entity) { + newSecretVersion := GetNewVersion(s.CurrentVersion) + s.CurrentVersion = newSecretVersion + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = newSecretVersion + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = updater + secretVersion.Updated = updater + s.Updated = updater + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) GetActiveVersion() MariaDBSecretVersion { + return s.Versions[s.CurrentVersion] +} +func (s *MariaDBSecretEntry) GetVersion(keyVersion string) MariaDBSecretVersion { + return s.Versions[keyVersion] +} + +// END INTEGRATION MARIADB STRUCTS diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9782f2d --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,316 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/integrationTests/client/client.go b/integrationTests/client/client.go new file mode 100644 index 0000000..70d4bee --- /dev/null +++ b/integrationTests/client/client.go @@ -0,0 +1,30 @@ +package integrationClient + +import ( + "fmt" + "log" + "os" + "time" + + "github.com/hashicorp/vault-client-go" +) + +func InitVaultClient() (*vault.Client){ + + // prepare a client with the given base address + client, err := vault.New( + vault.WithAddress(VaultConfig.Url+":"+fmt.Sprint(VaultConfig.Port)), + vault.WithRequestTimeout(30*time.Second), + ) + if err != nil { + log.Fatal(err) + os.Exit(1); + } + + // authenticate with a root token (insecure) + if err := client.SetToken(VaultConfig.RootToken); err != nil { + log.Fatal(err) + os.Exit(1); + } + return client; +} \ No newline at end of file diff --git a/integrationTests/client/client_config.go b/integrationTests/client/client_config.go new file mode 100644 index 0000000..148f2a9 --- /dev/null +++ b/integrationTests/client/client_config.go @@ -0,0 +1,15 @@ +package integrationClient + +type VaultClientConfig struct { + Port int + Url string + RootToken string + SecretsEnginePath string +} + +var VaultConfig VaultClientConfig=VaultClientConfig{ + Port: 8251, + Url: "http://127.0.0.1", + RootToken: "root", + SecretsEnginePath: "securosys-hsm", +} \ No newline at end of file diff --git a/integrationTests/client/go.mod b/integrationTests/client/go.mod new file mode 100644 index 0000000..02d12cd --- /dev/null +++ b/integrationTests/client/go.mod @@ -0,0 +1,24 @@ +module securosys.ch/integration/client + +go 1.21 + +toolchain go1.21.2 + +require github.com/hashicorp/vault-client-go v0.4.2 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stretchr/testify v1.8.2 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect +) diff --git a/integrationTests/client/go.sum b/integrationTests/client/go.sum new file mode 100644 index 0000000..3a52bd0 --- /dev/null +++ b/integrationTests/client/go.sum @@ -0,0 +1,58 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/vault-client-go v0.4.2 h1:XeUXb5jnDuCUhC8HRpkdGPLh1XtzXmiOnF0mXEbARxI= +github.com/hashicorp/vault-client-go v0.4.2/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integrationTests/docker/docker-compose.yml b/integrationTests/docker/docker-compose.yml new file mode 100644 index 0000000..f3d4294 --- /dev/null +++ b/integrationTests/docker/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.0" +name: hashicorp-vault-test-containers +services: + hashicorp-vault-test: + image: hashicorp/vault:latest + container_name: "hashicorp-vault-test" + environment: + VAULT_DEV_ROOT_TOKEN_ID: root + VAULT_ADDR: 'https://0.0.0.0:8251' + VAULT_LOCAL_CONFIG: '{"listener": [{"tcp":{"address": "0.0.0.0:8251","tls_disable":"1"}}], "default_lease_ttl": "168h", "max_lease_ttl": "720h"}, "ui": true}' + volumes: + - ./plugins/:/vault/plugins + cap_add: + - IPC_LOCK + healthcheck: + retries: 5 + ports: + - "8251:8251" + privileged: true + command: server -dev -dev-root-token-id=root -dev-plugin-dir=/vault/plugins + # networks: + # - web + # mariadb-test-integration: + # build: + # dockerfile: ./docker-files/MariaDB_Dockerfile + # container_name: "mariadb-test-integration" + # restart: always + # environment: + # MARIADB_ROOT_PASSWORD: example + # volumes: + # - ./mysql-config:/etc/mysql/conf.d + # - ./db:/var/lib/mysql + # networks: + # - web + +# networks: +# web: +# external: true + \ No newline at end of file diff --git a/integrationTests/docker/docker-files/MariaDB_Dockerfile b/integrationTests/docker/docker-files/MariaDB_Dockerfile new file mode 100644 index 0000000..7e5d37a --- /dev/null +++ b/integrationTests/docker/docker-files/MariaDB_Dockerfile @@ -0,0 +1,2 @@ +FROM mariadb:latest +RUN apt-get update && apt-get install -y mariadb-plugin-hashicorp-key-management diff --git a/integrationTests/docker/mysql-config/hashicorp.cnf b/integrationTests/docker/mysql-config/hashicorp.cnf new file mode 100644 index 0000000..1210099 --- /dev/null +++ b/integrationTests/docker/mysql-config/hashicorp.cnf @@ -0,0 +1,18 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="http://172.17.0.3:8251/v1/securosys-hsm/integrations/mariadb/test_async/?cipher_algorithm=RSA&key_name=rsa_with_policy&version=" +loose-hashicorp-key-management-token="root" +loose-hashicorp-key-management-check-kv-version="off" +loose-hashicorp-key-management-timeout=10 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +loose-hashicorp-key-management-cache-timeout=31556952000 +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = OFF +innodb_encrypt_log = OFF +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 diff --git a/integrationTests/tests/a_enable_plugin_test.go b/integrationTests/tests/a_enable_plugin_test.go new file mode 100644 index 0000000..d16575a --- /dev/null +++ b/integrationTests/tests/a_enable_plugin_test.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "testing" + + "github.com/hashicorp/vault-client-go/schema" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestEnablePlugin(t *testing.T) { + + t.Run("A.1 Test Enable Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.System.MountsEnableSecretsEngine(ctx,integrationClient.VaultConfig.SecretsEnginePath,schema.MountsEnableSecretsEngineRequest{ + Type: "securosys-hsm", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/b_config_plugin_test.go b/integrationTests/tests/b_config_plugin_test.go new file mode 100644 index 0000000..d777766 --- /dev/null +++ b/integrationTests/tests/b_config_plugin_test.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfigPlugin(t *testing.T) { + + t.Run("B.1 Test Config Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/config",testHelpers.ConfigParams) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data["result"]==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s","null").Error()) + } + + if(!strings.Contains(resp.Data["result"].(string),"Connection successful:")){ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s",resp.Data["result"]).Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_aes_key_test.go b/integrationTests/tests/c_create_aes_key_test.go new file mode 100644 index 0000000..ccffd1b --- /dev/null +++ b/integrationTests/tests/c_create_aes_key_test.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateAESKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_aes"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_aes got %s","null").Error()) + } + }) + t.Run("C.3 Read AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["secretKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Key Secret got %s","null").Error()) + } + }) + t.Run("C.8 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_key_by_keyname_test.go b/integrationTests/tests/c_create_key_by_keyname_test.go new file mode 100644 index 0000000..285e47c --- /dev/null +++ b/integrationTests/tests/c_create_key_by_keyname_test.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateKeyByKeyNamePlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with label integrationTestKeyRSAName using name rsa-2048", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/type/rsa-2048/integration_test_key_rsa_name",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSAName", + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSAName"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSAName",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSAName_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test Remove Key RSA Key with name integrationTestKeyRSAName", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa_name",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_rsa_key_test.go b/integrationTests/tests/c_create_rsa_key_test.go new file mode 100644 index 0000000..90c1a10 --- /dev/null +++ b/integrationTests/tests/c_create_rsa_key_test.go @@ -0,0 +1,250 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["publicKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Public Key got %s","null").Error()) + } + if(resp.Data["privateKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Private Key got %s","null").Error()) + } + }) + t.Run("C.8 Update password RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/update-password",map[string]interface{}{ + "password":"", + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Test Remove Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_smart_rsa_key_test.go b/integrationTests/tests/c_create_smart_rsa_key_test.go new file mode 100644 index 0000000..dfdd792 --- /dev/null +++ b/integrationTests/tests/c_create_smart_rsa_key_test.go @@ -0,0 +1,255 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateSmartRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_smart_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_smart_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Block Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/block",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.8 UnBlock Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/unblock",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Update password Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/update-password",map[string]interface{}{ + "password":nil, + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/d_operations_on_key_test.go b/integrationTests/tests/d_operations_on_key_test.go new file mode 100644 index 0000000..8dc951b --- /dev/null +++ b/integrationTests/tests/d_operations_on_key_test.go @@ -0,0 +1,329 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestOperationsOnKeyPlugin(t *testing.T) { + + t.Run("D.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.2 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.3 Test Encrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.4 Test Encrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.5 Test Decrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.6 Test Decrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_key_aes",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.7 Test Sign using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + }) + t.Run("D.8 Test Verify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/verify/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "keyVersion":"v1", + "signatureAlgorithm":"SHA256_WITH_RSA", + "signature":resp.Data["signature"].(string), + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid got %s","null").Error()) + } + if(resp.Data["signatureValid"]==false){ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid %s got %s","true",resp.Data["signatureValid"]).Error()) + } + }) + t.Run("D.9 Test Modify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/modify",map[string]interface{}{ + "simplePolicy":`{"test":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnydX62tLYNF+Op1SRnX6avkkyQWlpYPagH85zxaGnMlZoMioqgjSOCuRvjaP7Y5noPMYayp3gJ2PwLXvw9+JlnL+iwklOcpONSa6gDoCDsk26DOoY0ELEPaGdW61mc2bj2hOQE0GEpPsRywJoRLS3B2e8bqRfAniAfGsUq3MK09iL5YOCuUCHCUiR9iZMSt0+Ek/kE4TrazbOCev1g6Ux2vOyTuQ6mF3wVuqwd8RhfvlNNKXbD2GD/jR3BwuhaodwzRPmDyDQPmEMwornxrMLavTcC+Igb4k5qol0Di6Oq8axpBvrH7KlxHT11Wd+ALKCsqoPSGxcIbd6TdN+ag9AQIDAQAB"}`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.11 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/go.mod b/integrationTests/tests/go.mod new file mode 100644 index 0000000..02bc999 --- /dev/null +++ b/integrationTests/tests/go.mod @@ -0,0 +1,6 @@ +module securosys.ch/integration/tests + +replace securosys.ch/integration/client => ./../client +replace securosys.ch/test-helpers => ./../../testHelpers + +go 1.19 diff --git a/integrationTests/tests/go.sum b/integrationTests/tests/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/junit_report.xml b/junit_report.xml new file mode 100644 index 0000000..e69de29 diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..0111058 --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.1.0 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..0ace864 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/go.work b/tests/go.work new file mode 100644 index 0000000..7c33c4f --- /dev/null +++ b/tests/go.work @@ -0,0 +1,5 @@ +go 1.21 + +use ( + ./ +) \ No newline at end of file diff --git a/tests/go.work.sum b/tests/go.work.sum new file mode 100644 index 0000000..aff7933 --- /dev/null +++ b/tests/go.work.sum @@ -0,0 +1,163 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} diff --git a/tests/path_mariadb_integration_test.go b/tests/path_mariadb_integration_test.go new file mode 100644 index 0000000..b9b856e --- /dev/null +++ b/tests/path_mariadb_integration_test.go @@ -0,0 +1,111 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIntegrationMariaDB(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("A) add config", testEnv.AddConfig) + + t.Run("B) Test Creating RSA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + }) + t.Run("C)Add generate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("D)Read secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "integrations/mariadb/test/v1?key_name=custom_rsa_2048&cipher_algorithm=RSA", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("E) Rotate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("F) List secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "integrations/mariadb", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("G) Delete secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "integrations/mariadb/test", + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("H) Test Delete RSA key", func(t *testing.T) { + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + assert.NoError(t, err) + }) +} From 337c46630ad0232fc662974188dbd534c2836e53 Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Tue, 16 Jan 2024 09:25:50 +0100 Subject: [PATCH 06/16] Release v.1.0.3 --- .github/ISSUE_TEMPLATE/bug-report-sse.md | 49 + .github/ISSUE_TEMPLATE/feature-request-sse.md | 33 + .gitignore | 4 + LICENSE | 201 ++ Makefile | 169 + Readme.md | 983 ++++++ backend/backend.go | 139 + backend/go.mod | 62 + backend/go.sum | 223 ++ backend/path_config.go | 274 ++ backend/path_help.go | 425 +++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 ++ backend/path_hsm_key_bls.go | 259 ++ backend/path_hsm_key_camellia.go | 226 ++ backend/path_hsm_key_chacha20.go | 208 ++ backend/path_hsm_key_dsa.go | 273 ++ backend/path_hsm_key_ec.go | 270 ++ backend/path_hsm_key_ed.go | 271 ++ backend/path_hsm_key_import.go | 306 ++ backend/path_hsm_key_rsa.go | 273 ++ backend/path_hsm_key_tdea.go | 208 ++ backend/path_hsm_key_with_name.go | 295 ++ backend/path_hsm_keys.go | 1359 ++++++++ backend/path_hsm_operations.go | 1631 ++++++++++ backend/path_hsm_requests.go | 298 ++ client/client.go | 48 + client/client_tsb.go | 1011 ++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + etc/example/policy.json | 93 + etc/release_notes/Release_Notes.md | 20 + go.mod | 22 + go.sum | 2754 +++++++++++++++++ helpers/consts.go | 53 + helpers/functions.go | 191 ++ helpers/go.mod | 57 + helpers/go.sum | 223 ++ helpers/structs.go | 315 ++ project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 ++ testHelpers/test_client_tsb.go | 151 + testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 +++++ tests/go.mod | 66 + tests/go.sum | 223 ++ tests/path_config_test.go | 153 + tests/path_hsm_key_aes_test.go | 133 + tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 + tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 + tests/path_hsm_key_tdea_test.go | 136 + tests/path_hsm_key_using_type_name_test.go | 245 ++ tests/path_hsm_keys_rotation_test.go | 836 +++++ tests/path_hsm_keys_test.go | 312 ++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++ tests/path_hsm_operations_sign_test.go | 647 ++++ tests/path_hsm_operations_unwrap_test.go | 675 ++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++ tests/path_hsm_operations_wrap_test.go | 242 ++ tests/path_hsm_requests_test.go | 299 ++ 69 files changed, 22677 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-sse.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-sse.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/structs.go create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go diff --git a/.github/ISSUE_TEMPLATE/bug-report-sse.md b/.github/ISSUE_TEMPLATE/bug-report-sse.md new file mode 100644 index 0000000..40777e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-sse.md @@ -0,0 +1,49 @@ +--- +name: Bug report SSE +about: Create a report to help us improve +title: "[BUG] " +labels: '' +assignees: Peter-FNet + +--- + + + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment:** +* Vault Server Version (retrieve with `vault status`): +* Vault CLI Version (retrieve with `vault version`): +* Server Operating System/Architecture: + +Vault server configuration file(s): + +```hcl +# Paste your Vault config here. +# Be sure to scrub any sensitive values +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request-sse.md b/.github/ISSUE_TEMPLATE/feature-request-sse.md new file mode 100644 index 0000000..8264e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-sse.md @@ -0,0 +1,33 @@ +--- +name: Feature request SSE +about: Suggest an idea for this project +title: "[FEAT]" +labels: '' +assignees: Peter-FNet + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Explain any additional use-cases** +If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5375b60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +builds +vault +deploy +.gitlab-ci.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0cbf67f --- /dev/null +++ b/Makefile @@ -0,0 +1,169 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` + +ifndef ARTIFACT_NAME +override ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +endif + +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + echo "Finished!"; + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 15m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..6a06f46 --- /dev/null +++ b/Readme.md @@ -0,0 +1,983 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Appendix +### Frequently Asked Questions + +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..92d0f39 --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,139 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..7dba7ce --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,274 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "io/ioutil" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := ioutil.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} + diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..a26e88a --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,425 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + + + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} \ No newline at end of file diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..dca8ab1 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} \ No newline at end of file diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..41d1aa7 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} \ No newline at end of file diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..3025b53 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1011 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + `+passwordString+` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + `+passwordString+` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString:=""; + if(len(keyToBeWrappedPasswordJson)>2){ + keyToBeWrappedPasswordString=`"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString:=""; + if(len(wrapKeyPasswordJson)>2){ + wrapKeyPasswordString=`"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + `+keyToBeWrappedPasswordString+` + "wrapKeyName": "` + wrapKeyName + `", + `+wrapKeyPasswordString+` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + `+passwordString+` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + `+passwordString+` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + `+passwordString+` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + `+passwordString+` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + `+passwordString+` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + `+passwordString+` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + `+passwordString+` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + `+passwordString+` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + `+passwordString+` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + `+passwordString+` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + `+passwordString+` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + `+passwordString+` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString:=""; + if(len(charsNewPasswordJson)>2){ + newPasswordString=`"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + `+passwordString+newPasswordString+` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + `+passwordString+` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo) + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + `+passwordString+` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString:=""; + if(len(charsPasswordJson)>2){ + passwordString=`"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + `+passwordString+` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..8e00e02 --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,93 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..8aa2a7e --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,20 @@ +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d7aecd8 --- /dev/null +++ b/go.mod @@ -0,0 +1,22 @@ +module secretengine + +go 1.16 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers +replace securosys.ch/tests => ./tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8938e00 --- /dev/null +++ b/go.sum @@ -0,0 +1,2754 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20221206110420-d395f97c4830/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= +github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20221215162035-5330a85ea652/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v56.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= +github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= +github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= +github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= +github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.9.3/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.9.4/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.9.6/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.10.0-rc.7/go.mod h1:ILuwjA+kNW+MrN/w5un7n3mTqkwsFu4Bp05/okFUZlE= +github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= +github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk= +github.com/alexflint/go-filemutex v1.2.0/go.mod h1:mYyQSWvw9Tx2/H2n9qXPb52tTYfE0pZAWcBq5mK025c= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220418222510-f25a4f6275ed/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.43.16/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/bytecodealliance/wasmtime-go v0.36.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI= +github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/container-orchestrated-devices/container-device-interface v0.5.4/go.mod h1:DjE95rfPiiSmG7uVXtg0z6MnPm/Lx4wxKCIts0ZE0vg= +github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= +github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= +github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= +github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/btrfs/v2 v2.0.0/go.mod h1:swkD/7j9HApWpzl8OHfrHNxppPd9l44DFZdF94BUj9k= +github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/containerd/cgroups/v3 v3.0.1/go.mod h1:/vtwk1VXrtoa5AaZLkypuOJgA/6DyPMZHJPGQNtlHnw= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= +github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= +github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= +github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= +github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= +github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= +github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s= +github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE= +github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0= +github.com/containerd/containerd v1.6.8/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0= +github.com/containerd/containerd v1.6.9/go.mod h1:XVicUvkxOrftE2Q1YWUXgZwkkAxwQYNOFzYWvfVfEfQ= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= +github.com/containerd/continuity v0.2.2/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= +github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= +github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk= +github.com/containerd/go-cni v1.1.0/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA= +github.com/containerd/go-cni v1.1.3/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA= +github.com/containerd/go-cni v1.1.6/go.mod h1:BWtoWl5ghVymxu6MBjg79W9NZrCRyHIdUtk4cauMe34= +github.com/containerd/go-cni v1.1.9/go.mod h1:XYrZJ1d5W6E2VOvjffL3IZq0Dz6bsVlERHbekNK90PM= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= +github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= +github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow= +github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms= +github.com/containerd/imgcrypt v1.1.3/go.mod h1:/TPA1GIDXMzbj01yd8pIbQiLdQxed5ue1wb8bP7PQu4= +github.com/containerd/imgcrypt v1.1.4/go.mod h1:LorQnPtzL/T0IyCeftcsMEO7AqxUDbdO8j/tSUpgxvo= +github.com/containerd/imgcrypt v1.1.7/go.mod h1:FD8gqIcX5aTotCtOmjeCsi3A1dHmTZpnMISGKSczt4k= +github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= +github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/nri v0.3.0/go.mod h1:Zw9q2lP16sdg0zYybemZ9yTDy8g7fPCIB3KXOGlggXI= +github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM= +github.com/containerd/stargz-snapshotter/estargz v0.12.1/go.mod h1:12VUuCq3qPq4y8yUW+l5w3+oXV3cx2Po3KSe/SmPGqw= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= +github.com/containerd/ttrpc v1.1.1-0.20220420014843-944ef4a40df3/go.mod h1:YYyNVhZrTMiaf51Vj6WhAJqJw+vl/nzABhj8pWrzle4= +github.com/containerd/ttrpc v1.2.1/go.mod h1:sIT6l32Ph/H9cvnJsfXM5drIVzTr5A2flTf1G5tYZak= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containerd/typeurl/v2 v2.1.0/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= +github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= +github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= +github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y= +github.com/containernetworking/cni v1.1.1/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= +github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= +github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= +github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= +github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNBDZcxSOplJT5ico8/FLE= +github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8= +github.com/containernetworking/plugins v1.2.0/go.mod h1:/VjX4uHecW5vVimFa1wkG4s+r/s9qIfPdqlLF4TW8c4= +github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= +github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= +github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/containers/ocicrypt v1.1.3/go.mod h1:xpdkbVAuaH3WzbEabUd5yDsl9SwJA5pABH85425Es2g= +github.com/containers/ocicrypt v1.1.6/go.mod h1:WgjxPWdTJMqYMjf3M6cuIFFA1/MpyyhIM99YInA+Rvc= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= +github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= +github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M= +github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/distribution/distribution/v3 v3.0.0-20220526142353-ffbd94cbe269/go.mod h1:28YO/VJk9/64+sTGNuYaBjWxrXTPrj0C0XmgTIOjxX4= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.20+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.20+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= +github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/foxcpp/go-mockdns v0.0.0-20210729171921-fb145fc6f897/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-ini/ini v1.66.6/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/cel-go v0.12.6/go.mod h1:Jk7ljRzLBhkmiAwBoUxB1sZSCVBAzkqPF25olK/iRDw= +github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= +github.com/google/go-containerregistry v0.13.0/go.mod h1:J9FQ+eSS4a1aC2GNZxvNpbWhgp0487v+cgiilB4FqDo= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= +github.com/intel/goresctrl v0.3.0/go.mod h1:fdz3mD85cmP9sHD8JUlrNWAxvwM86CrbmVXltEKd7zk= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= +github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= +github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= +github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= +github.com/lestrrat-go/jwx v1.2.25/go.mod h1:zoNuZymNl5lgdcu6P7K6ie2QRll5HVfF4xwxBBK1NxY= +github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= +github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= +github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/networkplumbing/go-nft v0.2.0/go.mod h1:HnnM+tYvlGAsMU7yoYwXEVLLiDW9gdMmb5HoGcwpuQs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= +github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= +github.com/onsi/ginkgo/v2 v2.6.1/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= +github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= +github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= +github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= +github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk= +github.com/open-policy-agent/opa v0.42.2/go.mod h1:MrmoTi/BsKWT58kXlVayBb+rYVeaMwuBm3nYAN3923s= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runc v1.1.4/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.1.0-rc.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626/go.mod h1:BRHJJd0E+cx42OybVYSgUvZmU0B8P9gZuRXlZUP7TKI= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/peterh/liner v0.0.0-20170211195444-bf27d3ba8e1d/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/safchain/ethtool v0.2.0/go.mod h1:WkKB1DnNtvsMlDmQ50sgwowDJV/hGbJSOvJoEXs1AJQ= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.19.1/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= +github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= +github.com/vektah/gqlparser/v2 v2.4.5/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0= +github.com/veraison/go-cose v1.0.0-rc.1/go.mod h1:7ziE85vSq4ScFTg6wyoMXjucIGOf4JkFEZi/an96Ct4= +github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yashtewari/glob-intersection v0.1.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.5/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v2 v2.305.5/go.mod h1:zQjKllfqfBVyVStbt4FaosoX2iYd8fV/GRy/PbowgP4= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/client/v3 v3.5.5/go.mod h1:aApjR4WGlSumpnJ2kloS75h6aHUmAyaPLjHMxpc7E7c= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/pkg/v3 v3.5.5/go.mod h1:6ksYFxttiUGzC2uxyqiyOEvhAiD0tuIqSZkX3TyPdaE= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/raft/v3 v3.5.5/go.mod h1:76TA48q03g1y1VpTue92jZLr9lIHKUNcYdZOOGyx8rI= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= +go.etcd.io/etcd/server/v3 v3.5.5/go.mod h1:rZ95vDw/jrvsbj9XpTqPrTAB9/kzchVdhRirySPkUBc= +go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0/go.mod h1:h8TWwRAhQpOd0aM5nYsRD8+flnkj+526GEIVlarH7eY= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0/go.mod h1:UMklln0+MRhZC4e3PwmN3pCtq4DyIadWw4yikh6bNrw= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0/go.mod h1:5eCOqeGphOyz6TsY3ZDNjE33SM/TFAK3RGuCL2naTgY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.35.0/go.mod h1:9NiG9I2aHTKkcxqCILhjtyNA1QEiCjdBACv4IvrFQ+c= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU= +go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= +go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= +go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM= +go.opentelemetry.io/otel v1.10.0/go.mod h1:NbvWjCthWHKBEUMpf0/v8ZRZlni86PpGFEMA9pnQSnQ= +go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0/go.mod h1:M1hVZHNxcbkAlcvrOMlpQ4YOO3Awf+4N2dxkZL3xm04= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0/go.mod h1:78XhIg8Ht9vR4tbLNUhXsiOnE2HOuSeKAiAcoVQEpOY= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0/go.mod h1:UFG7EBMRdXyFstOwH028U0sVf+AvukSGhF0g8+dmNG8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0/go.mod h1:ceUgdyfNv4h4gLxHR0WNfDiiVmZFodZhZSbOLhpxqXE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.10.0/go.mod h1:Krqnjl22jUJ0HgMzw5eveuCvFDXY4nSYb4F8t5gdrag= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0/go.mod h1:HrbCVv40OOLTABmOn1ZWty6CHXkU8DK/Urc43tHug70= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0/go.mod h1:E+/KKhwOSw8yoPxSSuUHG6vKppkvhN+S1Jc7Nib3k3o= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.10.0/go.mod h1:OfUCyyIiDvNXHWpcWgbF+MWvqPZiNa3YDEnivcnYsV0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0/go.mod h1:5w41DY6S9gZrbjuq6Y+753e96WfPha5IcsOSZTtullM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0/go.mod h1:+N7zNjIJv4K+DeX67XXET0P+eIciESgaFDBqh+ZJFS4= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/metric v0.30.0/go.mod h1:/ShZ7+TS4dHzDFmfi1kSXMhMVubNoP0oIaBp70J6UXU= +go.opentelemetry.io/otel/metric v0.31.0/go.mod h1:ohmwj9KTSIeBnDBm/ZwH2PSZxZzoOaG2xZeekTRzL5A= +go.opentelemetry.io/otel/metric v0.37.0/go.mod h1:DmdaHfGt54iV6UKxsV9slj2bBRJcKC1B1uvDLIioc1s= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI= +go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= +go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU= +go.opentelemetry.io/otel/sdk v1.10.0/go.mod h1:vO06iKzD5baltJz1zarxMCNHFpUlUiOy4s65ECtn6kE= +go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk= +go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk= +go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= +go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4= +go.opentelemetry.io/otel/trace v1.10.0/go.mod h1:Sij3YYczqAdz+EhmGhE6TpTxUO5/F/AzrK+kxfGqySM= +go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg= +go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220405210540-1e041c57c461/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= +k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= +k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= +k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= +k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= +k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= +k8s.io/apimachinery v0.25.0/go.mod h1:qMx9eAk0sZQGsXGu86fab8tZdffHbwUfsvzqKn4mfB0= +k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= +k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= +k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ= +k8s.io/apiserver v0.26.2/go.mod h1:GHcozwXgXsPuOJ28EnQ/jXEM9QeG6HT22YxSNmpYNh8= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= +k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= +k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= +k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= +k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= +k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= +k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI= +k8s.io/component-base v0.26.2/go.mod h1:DxbuIe9M3IZPRxPIzhch2m1eT7uFrSBJUBuVCQEBivs= +k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= +k8s.io/cri-api v0.23.1/go.mod h1:REJE3PSU0h/LOV1APBrupxrEJqnoxZC8KWzkBUHwrK4= +k8s.io/cri-api v0.25.0/go.mod h1:J1rAyQkSJ2Q6I+aBMOVgg2/cbbebso6FNa0UagiR0kc= +k8s.io/cri-api v0.25.3/go.mod h1:riC/P0yOGUf2K1735wW+CXs1aY2ctBgePtnnoFLd0dU= +k8s.io/cri-api v0.26.2/go.mod h1:Oo8O7MKFPNDxfDf2LmrF/3Hf30q1C6iliGuv3la3tIA= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kms v0.26.2/go.mod h1:69qGnf1NsFOQP07fBYqNLZklqEHSJF024JqYCaeVxHg= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= +modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= +oras.land/oras-go v1.2.0/go.mod h1:pFNs7oHp2dYsYMSS82HaX5l4mpnGO7hbpPN6EWH2ltc= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.35/go.mod h1:WxjusMwXlKzfAs4p9km6XJRndVt2FROgMVCE4cdohFo= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..1925e0e --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,191 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9249056 --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,315 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..ebd8a3d --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.0.3 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..b55e030 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_API_URL", + "auth": "TOKEN", + "bearertoken": "TSB_BEARER_TOKEN", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} From f0cc62dd322449f88fdde3c5e7483cdc397f4b34 Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Tue, 23 Jan 2024 12:17:59 +0100 Subject: [PATCH 07/16] Release v.1.1.0 --- .github/ISSUE_TEMPLATE/bug-report-sse.md | 49 + .github/ISSUE_TEMPLATE/feature-request-sse.md | 33 + .gitignore | 4 + LICENSE | 201 ++ Makefile | 200 ++ Readme.md | 1145 ++++++++++++ backend/backend.go | 140 ++ backend/go.mod | 62 + backend/go.sum | 223 +++ backend/path_config.go | 294 +++ backend/path_help.go | 452 +++++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 +++ backend/path_hsm_key_bls.go | 259 +++ backend/path_hsm_key_camellia.go | 225 +++ backend/path_hsm_key_chacha20.go | 208 +++ backend/path_hsm_key_dsa.go | 273 +++ backend/path_hsm_key_ec.go | 270 +++ backend/path_hsm_key_ed.go | 271 +++ backend/path_hsm_key_import.go | 306 ++++ backend/path_hsm_key_rsa.go | 273 +++ backend/path_hsm_key_tdea.go | 208 +++ backend/path_hsm_key_with_name.go | 295 +++ backend/path_hsm_keys.go | 1359 ++++++++++++++ backend/path_hsm_operations.go | 1631 +++++++++++++++++ backend/path_hsm_requests.go | 298 +++ backend/path_mariadb_integration.go | 666 +++++++ client/client.go | 48 + client/client_tsb.go | 1023 +++++++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + .../alpine3/docker-compose-alpine3.yml | 56 + docker-builder/build-in-docker.sh | 12 + etc/example/mariaDb.cfg | 22 + etc/example/policy.json | 93 + etc/release_notes/Release_Notes.md | 29 + go.mod | 80 + go.sum | 254 +++ go.work | 8 + go.work.sum | 164 ++ helpers/consts.go | 53 + helpers/functions.go | 234 +++ helpers/go.mod | 57 + helpers/go.sum | 223 +++ helpers/mariadb_structs.go | 82 + helpers/structs.go | 316 ++++ integrationTests/client/client.go | 30 + integrationTests/client/client_config.go | 15 + integrationTests/client/go.mod | 24 + integrationTests/client/go.sum | 58 + integrationTests/docker/docker-compose.yml | 39 + .../docker/docker-files/MariaDB_Dockerfile | 2 + .../docker/mysql-config/hashicorp.cnf | 18 + .../tests/a_enable_plugin_test.go | 48 + .../tests/b_config_plugin_test.go | 55 + .../tests/c_create_aes_key_test.go | 234 +++ .../tests/c_create_key_by_keyname_test.go | 93 + .../tests/c_create_rsa_key_test.go | 250 +++ .../tests/c_create_smart_rsa_key_test.go | 255 +++ .../tests/d_operations_on_key_test.go | 329 ++++ integrationTests/tests/go.mod | 6 + integrationTests/tests/go.sum | 0 project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 +++ testHelpers/test_client_tsb.go | 151 ++ testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 ++++++++ tests/go.mod | 66 + tests/go.sum | 223 +++ tests/go.work | 5 + tests/go.work.sum | 163 ++ tests/path_config_test.go | 153 ++ tests/path_hsm_key_aes_test.go | 133 ++ tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 ++ tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 ++ tests/path_hsm_key_tdea_test.go | 136 ++ tests/path_hsm_key_using_type_name_test.go | 245 +++ tests/path_hsm_keys_rotation_test.go | 836 +++++++++ tests/path_hsm_keys_test.go | 312 ++++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++++ tests/path_hsm_operations_sign_test.go | 647 +++++++ tests/path_hsm_operations_unwrap_test.go | 675 +++++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++++++++ tests/path_hsm_operations_wrap_test.go | 242 +++ tests/path_hsm_requests_test.go | 299 +++ tests/path_mariadb_integration_test.go | 111 ++ 95 files changed, 23285 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-sse.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-sse.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 backend/path_mariadb_integration.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 docker-builder/alpine3/docker-compose-alpine3.yml create mode 100644 docker-builder/build-in-docker.sh create mode 100644 etc/example/mariaDb.cfg create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 go.work create mode 100644 go.work.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/mariadb_structs.go create mode 100644 helpers/structs.go create mode 100644 integrationTests/client/client.go create mode 100644 integrationTests/client/client_config.go create mode 100644 integrationTests/client/go.mod create mode 100644 integrationTests/client/go.sum create mode 100644 integrationTests/docker/docker-compose.yml create mode 100644 integrationTests/docker/docker-files/MariaDB_Dockerfile create mode 100644 integrationTests/docker/mysql-config/hashicorp.cnf create mode 100644 integrationTests/tests/a_enable_plugin_test.go create mode 100644 integrationTests/tests/b_config_plugin_test.go create mode 100644 integrationTests/tests/c_create_aes_key_test.go create mode 100644 integrationTests/tests/c_create_key_by_keyname_test.go create mode 100644 integrationTests/tests/c_create_rsa_key_test.go create mode 100644 integrationTests/tests/c_create_smart_rsa_key_test.go create mode 100644 integrationTests/tests/d_operations_on_key_test.go create mode 100644 integrationTests/tests/go.mod create mode 100644 integrationTests/tests/go.sum create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/go.work create mode 100644 tests/go.work.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go create mode 100644 tests/path_mariadb_integration_test.go diff --git a/.github/ISSUE_TEMPLATE/bug-report-sse.md b/.github/ISSUE_TEMPLATE/bug-report-sse.md new file mode 100644 index 0000000..40777e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-sse.md @@ -0,0 +1,49 @@ +--- +name: Bug report SSE +about: Create a report to help us improve +title: "[BUG] " +labels: '' +assignees: Peter-FNet + +--- + + + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment:** +* Vault Server Version (retrieve with `vault status`): +* Vault CLI Version (retrieve with `vault version`): +* Server Operating System/Architecture: + +Vault server configuration file(s): + +```hcl +# Paste your Vault config here. +# Be sure to scrub any sensitive values +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request-sse.md b/.github/ISSUE_TEMPLATE/feature-request-sse.md new file mode 100644 index 0000000..8264e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-sse.md @@ -0,0 +1,33 @@ +--- +name: Feature request SSE +about: Suggest an idea for this project +title: "[FEAT]" +labels: '' +assignees: Peter-FNet + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Explain any additional use-cases** +If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5375b60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +builds +vault +deploy +.gitlab-ci.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1e9dff6 --- /dev/null +++ b/Makefile @@ -0,0 +1,200 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` + +ifndef ARTIFACT_NAME +override ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +endif + +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + make release-alpine3 + echo "Finished!"; + +release-alpine3: + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-amd64 + make clean-docker-builder IMAGE=amd64/golang + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-i386 + make clean-docker-builder IMAGE=i386/golang + +clean-docker-builder: + @if [ "$$(docker images | grep '$(IMAGE)')" != "" ]; then \ + docker rmi -f $$(docker images | grep '$(IMAGE)' | awk '{ print $$3}') 2> /dev/null || true ; \ + fi; + docker volume prune -f + docker container prune -f + +run-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml up --build -d +clean-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml down --remove-orphans --rmi all + docker volume prune -f + docker container prune -f +integration-tests: + rm -fr integrationTests/docker/plugins/securosys-hsm + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -o integrationTests/docker/plugins/securosys-hsm cmd/securosys-hsm/main.go + make run-docker-test-container + + sleep 5 + go install github.com/jstemmer/go-junit-report/v2@latest + cd integrationTests/tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}integration_junit_report.xml -set-exit-code + + + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 15m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4828e0e --- /dev/null +++ b/Readme.md @@ -0,0 +1,1145 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Integrations](#integrations) + - [MariaDB](#mariadb) + - [Example usage](#mariadb-usage-example) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate and `keypath` with local PATH to the key. +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for Certificate authorization**: +```shell +$ vault write securosys-hsm/config +auth="CERT" +certpath="local_absolute_path_to_certificate.pem" +keypath="local_absolute_path_to_private.key" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=CERT' \ +--data-urlencode 'certpath=local_absolute_path_to_certificate.pem' \ +--data-urlencode 'keypath=local_absolute_path_to_private.pem' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Integrations +### MariaDB +Encryption on MariaDB can be enabled using existing plugin [Hashicorp Key Management Plugin](https://mariadb.com/kb/en/hashicorp-key-management-plugin/) +This integration stores generated secret in Secrets engine, encrypted by provided key. +**Supported Key Types**/**Algorithm** combinations: +| Key Type | Algorithm | +|----------|:-------------:| +| **RSA** |RSA_PADDING_OAEP_WITH_SHA512
RSA
RSA_PADDING_OAEP_WITH_SHA224
RSA_PADDING_OAEP_WITH_SHA256
RSA_PADDING_OAEP_WITH_SHA1
RSA_PADDING_OAEP
RSA_PADDING_OAEP_WITH_SHA384
RSA_NO_PADDING| +|**AES**|AES_GCM
AES_CTR
AES_ECB
AES_CBC_NO_PADDING
AES | +| **CHACHA20** | CHACHA20
CHACHA20_AEAD| +| **CAMELLIA** | CAMELLIA
CAMELLIA_CBC_NO_PADDING
CAMELLIA_ECB | +|**TDEA**| TDEA_CBC
TDEA_ECB
TDEA_CBC_NO_PADDING | + +>**Note** - Plugin supports **asynchronous decrypt operation** using key type **RSA** with **policy** with setup **ruleUse**. Using the key with policy will **stop** the decrypt operation and **wait for approvals** to be collected. + +There are a **serval steps** that is needed to be done before setup encryption on MariaDB +1) [Create / Register key](#manage-keys) into **Secrets Engine** +1) Generate new **secret** and encrypt it using stored key + ```shell + $ vault write securosys-hsm/integrations/mariadb/{secret-name} + keyName={key-name-from-secret-engine} + cipherAlgorithm={cipher-algorithm} + [additionalAuthenticationData={additional-authentication-data}] + [tagLength={tag-length}] + [password={password-for-a-key}] + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/integrations/mariadb/{secret-name} ' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName={key-name-from-secret-engine}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + >**Note** - Every request on this endpoint using same **key name** and **secret name** will **rotate secret** +1) The last step is add this configuration to **my.cfg** + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" + loose-hashicorp-key-management-token="{vault_access_token}" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + >**Note** - In **loose-hashicorp-key-management-vault-url** url need to ends with **&version=**. Plugin from **MariaDB** automatically add to end of url **number of secret version** +#### MariaDB usage example +This example using default configuration for **Hashicorp Vault dev server**. +| Data | Value | +|----------|:-------------:| +| **vault address** | https://localhost:8200 | +| **vault access token** | root | +1) **Create key** *MariaDBEncryptionKey* with key size *4096* with attributes at last "decrypt" equals *true* on HSM and store it as *mariadb_encryption_key* on **Secrets engine** + ```shell + $ vault write securosys-hsm/keys/rsa/mariadb_encryption_key + keyLabel="MariaDBEncryptionKey" + keySize=4096 + attributes='{"decrypt": true,"sign": false,"unwrap": false,"derive": true,"sensitive": true,"extractable": false,"modifiable": false,"copyable": false,"destroyable": true}' + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/keys/rsa/mariadb_encryption_key' \ + --header 'X-Vault-Token: root' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel=MariaDBEncryptionKey' \ + --data-urlencode 'keySize=4096' \ + --data-urlencode 'attributes={ + "decrypt": true, + "sign": false, + "unwrap": false, + "derive": true, + "sensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": false, + "copyable": false, + "destroyable": true + }' + ``` +1) Generate new **secret** called *mariadb_secret* and **encrypt it** using cipher algorithm *RSA* and stored key *mariadb_encryption_key* in **Secrets engine** + ```shell + $ vault write securosys-hsm/integrations/mariadb/mariadb_secret + keyName=mariadb_encryption_key + cipherAlgorithm=RSA + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret ' \ + --header 'X-Vault-Token: root' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName=mariadb_encryption_key' \ + --data-urlencode 'cipherAlgorithm=RSA' + ``` +3. Configure **MariaDB plugin** "Hashicorp Key Management" in database configuration in **my.cnf** + + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret/?key_name=mariadb_encryption_key&cipher_algorithm=RSA&version=" + loose-hashicorp-key-management-token="root" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + + + +--- +## Appendix +### Frequently Asked Questions +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..67cf38a --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,140 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + pathMariaDBIntegration(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..29a1fac --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,294 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "keypath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to key", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "KeyPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if keypath, ok := data.GetOk("keypath"); ok { + config.KeyPath = keypath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing keypath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.KeyPath) + + if err != nil { + return nil, fmt.Errorf("Keypath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..8281fe0 --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,452 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..32954d9 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string), map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy, map[string]string{}) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil, map[string]string{}) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString, nil) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..e24fe58 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} diff --git a/backend/path_mariadb_integration.go b/backend/path_mariadb_integration.go new file mode 100644 index 0000000..0101c1d --- /dev/null +++ b/backend/path_mariadb_integration.go @@ -0,0 +1,666 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for create Camellia Keys +func pathMariaDBIntegration(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "keyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsDelete, + }, + }, + HelpSynopsis: pathIntegrationMariaDBWriteHelpSynopsis, + HelpDescription: pathIntegrationMariaDBWriteHelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("version") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV1HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV1HelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV2HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV2HelpDescription, + }, + { + Pattern: "integrations/mariadb/?$", + Fields: map[string]*framework.FieldSchema{}, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsList, + }, + }, + HelpSynopsis: pathIntegrationMariaDBListHelpSynopsis, + HelpDescription: pathIntegrationMariaDBListHelpDescription, + }, + } +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "intergration/mariadb/") + if err != nil { + return nil, err + } + secrets := make([]string, 0, len(entries)) + secretsInfo := make(map[string]interface{}) + for _, name := range entries { + secrets = append(secrets, name) + secret, err := b.GetMariaDBSecret(ctx, req.Storage, name) + if err == nil { + secretsInfo[name] = map[string]interface{}{ + "KeyName": secret.KeyName, + "Version": secret.CurrentVersion, + "Created": secret.Created.Name, + "Updated": secret.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(secrets, secretsInfo), nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, errGet := b.GetMariaDBSecret(ctx, req.Storage, name) + if errGet != nil { + return nil, fmt.Errorf("error deleting mariadb secret: %w", errGet) + } + if storedSecret == nil { + return nil, fmt.Errorf("error deleting mariadb secret: secret with name %s not exists", d.Get("name").(string)) + + } + + err := req.Storage.Delete(ctx, "intergration/mariadb/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + rotate := false + if storedSecret != nil { + rotate = true + // return nil, fmt.Errorf("error secret with name: %s exists", name) + } else { + storedSecret = &helpers.MariaDBSecretEntry{} + + } + + keyName := d.Get("keyName").(string) + + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload := b64.StdEncoding.EncodeToString([]byte(helpers.GeneratePassword(32, false, false, false, true))) + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + sysView := b.System() + creator := helpers.Entity{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + creator.Aliases = entity.Aliases + creator.Id = entity.ID + creator.Name = entity.Name + creator.Date = time.Now().UTC() + + } else { + creator.Aliases = nil + creator.Id = "root" + creator.Name = "root" + creator.Date = time.Now().UTC() + + } + var messageAuthenticationCode *string = nil + if result["messageAuthenticationCode"] != nil { + temp := result["messageAuthenticationCode"].(string) + messageAuthenticationCode = &temp + } + var initializationVector *string = nil + if result["initializationVector"] != nil { + temp := result["initializationVector"].(string) + initializationVector = &temp + } + if !rotate { + storedSecret.InitSecret(keyName, keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + } else { + storedSecret.RotateSecret(keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + + } + if err := SetMariaDBSecret(ctx, req.Storage, name, storedSecret); err != nil { + return nil, err + } + + response := map[string]interface{}{} + now := storedSecret.GetActiveVersion().Created.Date + version := storedSecret.GetActiveVersion().Version + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + query := d.Get("query").(string) + if strings.HasPrefix(query, "?") { + query = query[1:] + } + params, err := url.ParseQuery(query) + + if query == "" { + str := "" + for key, value := range req.Data { + str = str + key + "=" + value.(string) + "&" + } + str = str[:len(str)-1] + params, err = url.ParseQuery(str) + } + + if err != nil { + return nil, err + } + name := d.Get("name").(string) + + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + if storedSecret == nil { + return nil, fmt.Errorf("error secret with name: %s not exists", name) + } + + version := "1" + if params.Has("version") { + if !strings.Contains(params.Get("version"), "?version=") { + version = storedSecret.CurrentVersion + } else { + parts := strings.Split(params.Get("version"), "?version=") + version = "v" + parts[1] + } + } else { + ver, ok := d.GetOk("version") + if !ok { + return nil, fmt.Errorf("error: missing version") + } + version = ver.(string) + } + + if !params.Has("key_name") { + return nil, fmt.Errorf("key_name query param not exists") + } + keyEntry, err := b.GetKey(ctx, req.Storage, params.Get("key_name")) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + keyName := params.Get("key_name") + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + + if !helpers.ContainsKey(storedSecret.Versions, version) { + return nil, fmt.Errorf("Secret version %s is not exists.", version) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload := storedSecret.GetVersion(version).EncryptedSecret + + if !params.Has("cipher_algorithm") { + return nil, fmt.Errorf("cipher_algorithm query param not exists") + } + + cipherAlgorithm := params.Get("cipher_algorithm") + if keyEntry.KeyTypeName != "aes256-gcm96" && cipherAlgorithm == "" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVectorString := "" + if params.Has("initialization_vector") { + initializationVectorString = params.Get("initialization_vector") + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + passwordString := "" + if params.Has("password") { + passwordString = params.Get("password") + } + tagLengthInt := -1 + if params.Has("tag_length") { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + } + if keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationDataString := "" + if params.Has("aad") { + additionalAuthenticationDataString = params.Get("aad") + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationDataString) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData (param aad) is not valid base64 string") + } + } + client, err := b.GetClient(ctx, req.Storage) + async := false + decrypted := "" + if len(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + async = true + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString, map[string]string{"integration": "MariaDB Encrypt"}) + if errEnc != nil { + return nil, errEnc + } + var resp *helpers.RequestResponse + resp, _, _ = client.GetRequest(requestId) + for resp.Status == "PENDING" { + time.Sleep(1000) + resp, _, _ = client.GetRequest(requestId) + } + if resp.Status != "EXECUTED" { + return nil, fmt.Errorf("error on async decrypt. Expected Status '%s' got '%s'", "EXECUTED", resp.Status) + } + decrypted = resp.Result + + } + } + } + if !async { + resultSync, errEnc := client.Decrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + decrypted = resultSync["payload"].(string) + } + + if cipherAlgorithm == "AES_ECB" || + cipherAlgorithm == "AES_CBC_NO_PADDING" || + cipherAlgorithm == "CAMELLIA_ECB" || + cipherAlgorithm == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + decoded, _ := base64.StdEncoding.DecodeString(decrypted) + response := map[string]interface{}{} + response["data"] = map[string]interface{}{"data": string(decoded)} + now := storedSecret.GetVersion(version).Created.Date + + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} + +// This function helps with saving key in Secrets Engine +func SetMariaDBSecret(ctx context.Context, s logical.Storage, name string, secretEntry *helpers.MariaDBSecretEntry) error { + entry, err := logical.StorageEntryJSON("intergration/mariadb/"+name, secretEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage secret") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetMariaDBSecret(ctx context.Context, s logical.Storage, name string) (*helpers.MariaDBSecretEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "intergration/mariadb/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var secret helpers.MariaDBSecretEntry + + if err := entry.DecodeJSON(&secret); err != nil { + return nil, err + } + return &secret, nil +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..b50c7e2 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1023 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + KeyPath: data["keypath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + ` + passwordString + ` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy, customMetaData map[string]string) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo, customMetaData) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString := "" + if len(keyToBeWrappedPasswordJson) > 2 { + keyToBeWrappedPasswordString = `"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString := "" + if len(wrapKeyPasswordJson) > 2 { + wrapKeyPasswordString = `"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + ` + keyToBeWrappedPasswordString + ` + "wrapKeyName": "` + wrapKeyName + `", + ` + wrapKeyPasswordString + ` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + ` + passwordString + ` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + ` + passwordString + ` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + ` + passwordString + ` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + ` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString := "" + if len(charsNewPasswordJson) > 2 { + newPasswordString = `"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + newPasswordString + ` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + passwordString + ` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + clientTLSCert, err := tls.LoadX509KeyPair(c.Auth.CertPath, c.Auth.KeyPath) + if err != nil { + log.Fatalf("Error loading certificate and key file: %v", err) + return nil, err, 0 + } + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + InsecureSkipVerify: true, + Certificates: []tls.Certificate{clientTLSCert}, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/docker-builder/alpine3/docker-compose-alpine3.yml b/docker-builder/alpine3/docker-compose-alpine3.yml new file mode 100644 index 0000000..1190d88 --- /dev/null +++ b/docker-builder/alpine3/docker-compose-alpine3.yml @@ -0,0 +1,56 @@ + version: "3.3" + services: + golang-builder-alpine3-amd64: + platform: linux/amd64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=amd64 + image: amd64/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-amd64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-i386: + platform: linux/i386 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=386 + image: i386/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-i386 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-arm64: + platform: linux/arm64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=arm64 + image: arm64v8/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-arm64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" \ No newline at end of file diff --git a/docker-builder/build-in-docker.sh b/docker-builder/build-in-docker.sh new file mode 100644 index 0000000..adc15b2 --- /dev/null +++ b/docker-builder/build-in-docker.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd .. +echo "Build ${ARTIFACT_NAME} in ${DOCKER_OS}_${DOCKER_ARCH}"; + cd /src + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; + cd builds; + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; + zip -9 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; + shasum -a 256 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; + cd ..; + rm builds/securosys-hsm; + rm builds/securosys-hsm_SHA256SUM; \ No newline at end of file diff --git a/etc/example/mariaDb.cfg b/etc/example/mariaDb.cfg new file mode 100644 index 0000000..298e73a --- /dev/null +++ b/etc/example/mariaDb.cfg @@ -0,0 +1,22 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" +loose-hashicorp-key-management-token="{vault_access_token}" +loose-hashicorp-key-management-check-kv-version="off" +#max timeout is 86400 seconds +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +#1 year in miliseconds +loose-hashicorp-key-management-cache-timeout=31556952000 +#1 year in miliseconds +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +#Example of innodb config +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = ON +innodb_encrypt_log = ON +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 \ No newline at end of file diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..8e00e02 --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,93 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..6eebb05 --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,29 @@ +# Securosys Hashicorp Vault Secrets Engine 1.1.0 +Issued: Dec, 6, 2023 +## Documentation Change +- Update Readme.md - added information about supporting and how to configure encryption on MariaDB +## Feature +- Added integration with MariaDB encryption +## Bugfix +- Fixed authentication with TSB using mTLS + +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build/ + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2d78c0c --- /dev/null +++ b/go.mod @@ -0,0 +1,80 @@ +module secretengine + +go 1.21 + +toolchain go1.21.2 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers + +replace securosys.ch/tests => ./tests + +replace securosys.ch/integration/client => ./integrationTests/client + +replace securosys.ch/integration/tests => ./integrationTests/tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/frankban/quicktest v1.14.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afae25d --- /dev/null +++ b/go.sum @@ -0,0 +1,254 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work new file mode 100644 index 0000000..ad36518 --- /dev/null +++ b/go.work @@ -0,0 +1,8 @@ +go 1.21 + +use ( + ./ + ./backend + ./integrationTests/client + ./integrationTests/tests +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..976ca94 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,164 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..bdc47e4 --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "math/rand" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} +func GetVersionNumber(version string) int { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + return versionInt +} +func GetVersionString(version string) string { + return strings.Replace(version, "v", "", 1) +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string, customMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + for key, value := range customMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + specialBytes = "!@#$%^&*()_+-=[]{}\\|;':\",.<>/?`~" + numBytes = "0123456789" + hexDecimalBytes = "0123456789ABCDEF" +) + +func GeneratePassword(length int, useLetters bool, useSpecial bool, useNum bool, useHexadecimal bool) string { + rand.Seed(time.Now().UnixNano()) + b := make([]byte, length) + arrayForRandom := make([]byte, 0) + if useLetters { + arrayForRandom = append(arrayForRandom, letterBytes...) + } + if useSpecial { + arrayForRandom = append(arrayForRandom, specialBytes...) + } + if useNum { + arrayForRandom = append(arrayForRandom, numBytes...) + } + if useHexadecimal { + arrayForRandom = append(arrayForRandom, hexDecimalBytes...) + + } + + for i := range b { + b[i] = arrayForRandom[rand.Intn(len(arrayForRandom))] + } + return string(b) +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/mariadb_structs.go b/helpers/mariadb_structs.go new file mode 100644 index 0000000..97210ac --- /dev/null +++ b/helpers/mariadb_structs.go @@ -0,0 +1,82 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// INTEGRATION MARIADB STRUCTS + +type MariaDBSecretEntry struct { + KeyName string `json:"keyName"` + Versions map[string]MariaDBSecretVersion `json:"secretVersions"` + CurrentVersion string `json:"defaultVersion"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +// Struct of keys stored inside the Vault +type MariaDBSecretVersion struct { + KeyVersion string `json:"keyVersion"` + EncryptedSecret string `json:"encryptedSecret"` + MessageAuthenticationCode *string `json:"messageAuthenticationCode"` + InitializationVector *string `json:"initializationVector"` + Version string `json:"version"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (s *MariaDBSecretEntry) InitSecret(keyName string, keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, creator Entity) { + s.CurrentVersion = "v1" + s.KeyName = keyName + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = "v1" + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = creator + secretVersion.Updated = creator + s.Created = creator + s.Updated = creator + s.Versions = make(map[string]MariaDBSecretVersion) + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) RotateSecret(keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, updater Entity) { + newSecretVersion := GetNewVersion(s.CurrentVersion) + s.CurrentVersion = newSecretVersion + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = newSecretVersion + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = updater + secretVersion.Updated = updater + s.Updated = updater + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) GetActiveVersion() MariaDBSecretVersion { + return s.Versions[s.CurrentVersion] +} +func (s *MariaDBSecretEntry) GetVersion(keyVersion string) MariaDBSecretVersion { + return s.Versions[keyVersion] +} + +// END INTEGRATION MARIADB STRUCTS diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9782f2d --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,316 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/integrationTests/client/client.go b/integrationTests/client/client.go new file mode 100644 index 0000000..70d4bee --- /dev/null +++ b/integrationTests/client/client.go @@ -0,0 +1,30 @@ +package integrationClient + +import ( + "fmt" + "log" + "os" + "time" + + "github.com/hashicorp/vault-client-go" +) + +func InitVaultClient() (*vault.Client){ + + // prepare a client with the given base address + client, err := vault.New( + vault.WithAddress(VaultConfig.Url+":"+fmt.Sprint(VaultConfig.Port)), + vault.WithRequestTimeout(30*time.Second), + ) + if err != nil { + log.Fatal(err) + os.Exit(1); + } + + // authenticate with a root token (insecure) + if err := client.SetToken(VaultConfig.RootToken); err != nil { + log.Fatal(err) + os.Exit(1); + } + return client; +} \ No newline at end of file diff --git a/integrationTests/client/client_config.go b/integrationTests/client/client_config.go new file mode 100644 index 0000000..148f2a9 --- /dev/null +++ b/integrationTests/client/client_config.go @@ -0,0 +1,15 @@ +package integrationClient + +type VaultClientConfig struct { + Port int + Url string + RootToken string + SecretsEnginePath string +} + +var VaultConfig VaultClientConfig=VaultClientConfig{ + Port: 8251, + Url: "http://127.0.0.1", + RootToken: "root", + SecretsEnginePath: "securosys-hsm", +} \ No newline at end of file diff --git a/integrationTests/client/go.mod b/integrationTests/client/go.mod new file mode 100644 index 0000000..02d12cd --- /dev/null +++ b/integrationTests/client/go.mod @@ -0,0 +1,24 @@ +module securosys.ch/integration/client + +go 1.21 + +toolchain go1.21.2 + +require github.com/hashicorp/vault-client-go v0.4.2 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stretchr/testify v1.8.2 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect +) diff --git a/integrationTests/client/go.sum b/integrationTests/client/go.sum new file mode 100644 index 0000000..3a52bd0 --- /dev/null +++ b/integrationTests/client/go.sum @@ -0,0 +1,58 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/vault-client-go v0.4.2 h1:XeUXb5jnDuCUhC8HRpkdGPLh1XtzXmiOnF0mXEbARxI= +github.com/hashicorp/vault-client-go v0.4.2/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integrationTests/docker/docker-compose.yml b/integrationTests/docker/docker-compose.yml new file mode 100644 index 0000000..1b00ff4 --- /dev/null +++ b/integrationTests/docker/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.0" +name: hashicorp-vault-test-containers +services: + hashicorp-vault-test: + image: hashicorp/vault:latest + container_name: "hashicorp-vault-test" + environment: + VAULT_DEV_ROOT_TOKEN_ID: root + VAULT_ADDR: 'https://0.0.0.0:8251' + VAULT_LOCAL_CONFIG: '{"listener": [{"tcp":{"address": "0.0.0.0:8251","tls_disable":"1"}}], "default_lease_ttl": "168h", "max_lease_ttl": "720h"}, "ui": true}' + volumes: + - ./plugins/:/vault/plugins + cap_add: + - IPC_LOCK + healthcheck: + retries: 5 + ports: + - "8251:8251" + privileged: true + command: server -dev -dev-root-token-id=root -dev-plugin-dir=/vault/plugins + networks: + - web + mariadb-test-integration: + build: + dockerfile: ./docker-files/MariaDB_Dockerfile + container_name: "mariadb-test-integration" + restart: always + environment: + MARIADB_ROOT_PASSWORD: example + volumes: + - ./mysql-config:/etc/mysql/conf.d + - ./db:/var/lib/mysql + networks: + - web + +networks: + web: + external: true + \ No newline at end of file diff --git a/integrationTests/docker/docker-files/MariaDB_Dockerfile b/integrationTests/docker/docker-files/MariaDB_Dockerfile new file mode 100644 index 0000000..7e5d37a --- /dev/null +++ b/integrationTests/docker/docker-files/MariaDB_Dockerfile @@ -0,0 +1,2 @@ +FROM mariadb:latest +RUN apt-get update && apt-get install -y mariadb-plugin-hashicorp-key-management diff --git a/integrationTests/docker/mysql-config/hashicorp.cnf b/integrationTests/docker/mysql-config/hashicorp.cnf new file mode 100644 index 0000000..d628bc7 --- /dev/null +++ b/integrationTests/docker/mysql-config/hashicorp.cnf @@ -0,0 +1,18 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="http://192.168.96.3:8251/v1/securosys-hsm/integrations/mariadb/test_async/?cipher_algorithm=RSA&key_name=rsa_with_policy&version=" +loose-hashicorp-key-management-token="root" +loose-hashicorp-key-management-check-kv-version="off" +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +loose-hashicorp-key-management-cache-timeout=31556952000 +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = OFF +innodb_encrypt_log = OFF +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 diff --git a/integrationTests/tests/a_enable_plugin_test.go b/integrationTests/tests/a_enable_plugin_test.go new file mode 100644 index 0000000..d16575a --- /dev/null +++ b/integrationTests/tests/a_enable_plugin_test.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "testing" + + "github.com/hashicorp/vault-client-go/schema" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestEnablePlugin(t *testing.T) { + + t.Run("A.1 Test Enable Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.System.MountsEnableSecretsEngine(ctx,integrationClient.VaultConfig.SecretsEnginePath,schema.MountsEnableSecretsEngineRequest{ + Type: "securosys-hsm", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/b_config_plugin_test.go b/integrationTests/tests/b_config_plugin_test.go new file mode 100644 index 0000000..d777766 --- /dev/null +++ b/integrationTests/tests/b_config_plugin_test.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfigPlugin(t *testing.T) { + + t.Run("B.1 Test Config Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/config",testHelpers.ConfigParams) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data["result"]==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s","null").Error()) + } + + if(!strings.Contains(resp.Data["result"].(string),"Connection successful:")){ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s",resp.Data["result"]).Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_aes_key_test.go b/integrationTests/tests/c_create_aes_key_test.go new file mode 100644 index 0000000..ccffd1b --- /dev/null +++ b/integrationTests/tests/c_create_aes_key_test.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateAESKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_aes"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_aes got %s","null").Error()) + } + }) + t.Run("C.3 Read AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["secretKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Key Secret got %s","null").Error()) + } + }) + t.Run("C.8 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_key_by_keyname_test.go b/integrationTests/tests/c_create_key_by_keyname_test.go new file mode 100644 index 0000000..285e47c --- /dev/null +++ b/integrationTests/tests/c_create_key_by_keyname_test.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateKeyByKeyNamePlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with label integrationTestKeyRSAName using name rsa-2048", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/type/rsa-2048/integration_test_key_rsa_name",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSAName", + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSAName"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSAName",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSAName_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test Remove Key RSA Key with name integrationTestKeyRSAName", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa_name",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_rsa_key_test.go b/integrationTests/tests/c_create_rsa_key_test.go new file mode 100644 index 0000000..90c1a10 --- /dev/null +++ b/integrationTests/tests/c_create_rsa_key_test.go @@ -0,0 +1,250 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["publicKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Public Key got %s","null").Error()) + } + if(resp.Data["privateKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Private Key got %s","null").Error()) + } + }) + t.Run("C.8 Update password RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/update-password",map[string]interface{}{ + "password":"", + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Test Remove Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_smart_rsa_key_test.go b/integrationTests/tests/c_create_smart_rsa_key_test.go new file mode 100644 index 0000000..dfdd792 --- /dev/null +++ b/integrationTests/tests/c_create_smart_rsa_key_test.go @@ -0,0 +1,255 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateSmartRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_smart_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_smart_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Block Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/block",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.8 UnBlock Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/unblock",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Update password Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/update-password",map[string]interface{}{ + "password":nil, + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/d_operations_on_key_test.go b/integrationTests/tests/d_operations_on_key_test.go new file mode 100644 index 0000000..8dc951b --- /dev/null +++ b/integrationTests/tests/d_operations_on_key_test.go @@ -0,0 +1,329 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestOperationsOnKeyPlugin(t *testing.T) { + + t.Run("D.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.2 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.3 Test Encrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.4 Test Encrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.5 Test Decrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.6 Test Decrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_key_aes",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.7 Test Sign using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + }) + t.Run("D.8 Test Verify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/verify/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "keyVersion":"v1", + "signatureAlgorithm":"SHA256_WITH_RSA", + "signature":resp.Data["signature"].(string), + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid got %s","null").Error()) + } + if(resp.Data["signatureValid"]==false){ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid %s got %s","true",resp.Data["signatureValid"]).Error()) + } + }) + t.Run("D.9 Test Modify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/modify",map[string]interface{}{ + "simplePolicy":`{"test":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnydX62tLYNF+Op1SRnX6avkkyQWlpYPagH85zxaGnMlZoMioqgjSOCuRvjaP7Y5noPMYayp3gJ2PwLXvw9+JlnL+iwklOcpONSa6gDoCDsk26DOoY0ELEPaGdW61mc2bj2hOQE0GEpPsRywJoRLS3B2e8bqRfAniAfGsUq3MK09iL5YOCuUCHCUiR9iZMSt0+Ek/kE4TrazbOCev1g6Ux2vOyTuQ6mF3wVuqwd8RhfvlNNKXbD2GD/jR3BwuhaodwzRPmDyDQPmEMwornxrMLavTcC+Igb4k5qol0Di6Oq8axpBvrH7KlxHT11Wd+ALKCsqoPSGxcIbd6TdN+ag9AQIDAQAB"}`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.11 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/go.mod b/integrationTests/tests/go.mod new file mode 100644 index 0000000..02bc999 --- /dev/null +++ b/integrationTests/tests/go.mod @@ -0,0 +1,6 @@ +module securosys.ch/integration/tests + +replace securosys.ch/integration/client => ./../client +replace securosys.ch/test-helpers => ./../../testHelpers + +go 1.19 diff --git a/integrationTests/tests/go.sum b/integrationTests/tests/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..0111058 --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.1.0 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..b55e030 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_API_URL", + "auth": "TOKEN", + "bearertoken": "TSB_BEARER_TOKEN", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/go.work b/tests/go.work new file mode 100644 index 0000000..7c33c4f --- /dev/null +++ b/tests/go.work @@ -0,0 +1,5 @@ +go 1.21 + +use ( + ./ +) \ No newline at end of file diff --git a/tests/go.work.sum b/tests/go.work.sum new file mode 100644 index 0000000..aff7933 --- /dev/null +++ b/tests/go.work.sum @@ -0,0 +1,163 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} diff --git a/tests/path_mariadb_integration_test.go b/tests/path_mariadb_integration_test.go new file mode 100644 index 0000000..b9b856e --- /dev/null +++ b/tests/path_mariadb_integration_test.go @@ -0,0 +1,111 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIntegrationMariaDB(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("A) add config", testEnv.AddConfig) + + t.Run("B) Test Creating RSA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + }) + t.Run("C)Add generate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("D)Read secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "integrations/mariadb/test/v1?key_name=custom_rsa_2048&cipher_algorithm=RSA", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("E) Rotate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("F) List secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "integrations/mariadb", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("G) Delete secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "integrations/mariadb/test", + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("H) Test Delete RSA key", func(t *testing.T) { + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + assert.NoError(t, err) + }) +} From 7311d6a794717dc1aa7d732402d8f8ff885b4387 Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Wed, 24 Jan 2024 10:50:08 +0100 Subject: [PATCH 08/16] Release v.1.1.0 --- .github/ISSUE_TEMPLATE/bug-report-sse.md | 49 + .github/ISSUE_TEMPLATE/feature-request-sse.md | 33 + .gitignore | 4 + LICENSE | 201 ++ Makefile | 200 ++ Readme.md | 1145 ++++++++++++ backend/backend.go | 140 ++ backend/go.mod | 62 + backend/go.sum | 223 +++ backend/path_config.go | 294 +++ backend/path_help.go | 452 +++++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 +++ backend/path_hsm_key_bls.go | 259 +++ backend/path_hsm_key_camellia.go | 225 +++ backend/path_hsm_key_chacha20.go | 208 +++ backend/path_hsm_key_dsa.go | 273 +++ backend/path_hsm_key_ec.go | 270 +++ backend/path_hsm_key_ed.go | 271 +++ backend/path_hsm_key_import.go | 306 ++++ backend/path_hsm_key_rsa.go | 273 +++ backend/path_hsm_key_tdea.go | 208 +++ backend/path_hsm_key_with_name.go | 295 +++ backend/path_hsm_keys.go | 1359 ++++++++++++++ backend/path_hsm_operations.go | 1631 +++++++++++++++++ backend/path_hsm_requests.go | 298 +++ backend/path_mariadb_integration.go | 666 +++++++ client/client.go | 48 + client/client_tsb.go | 1023 +++++++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + .../alpine3/docker-compose-alpine3.yml | 56 + docker-builder/build-in-docker.sh | 12 + etc/example/mariaDb.cfg | 22 + etc/example/policy.json | 93 + etc/release_notes/Release_Notes.md | 29 + go.mod | 80 + go.sum | 254 +++ go.work | 8 + go.work.sum | 164 ++ helpers/consts.go | 53 + helpers/functions.go | 234 +++ helpers/go.mod | 57 + helpers/go.sum | 223 +++ helpers/mariadb_structs.go | 82 + helpers/structs.go | 316 ++++ integrationTests/client/client.go | 30 + integrationTests/client/client_config.go | 15 + integrationTests/client/go.mod | 24 + integrationTests/client/go.sum | 58 + integrationTests/docker/docker-compose.yml | 39 + .../docker/docker-files/MariaDB_Dockerfile | 2 + .../docker/mysql-config/hashicorp.cnf | 18 + .../tests/a_enable_plugin_test.go | 48 + .../tests/b_config_plugin_test.go | 55 + .../tests/c_create_aes_key_test.go | 234 +++ .../tests/c_create_key_by_keyname_test.go | 93 + .../tests/c_create_rsa_key_test.go | 250 +++ .../tests/c_create_smart_rsa_key_test.go | 255 +++ .../tests/d_operations_on_key_test.go | 329 ++++ integrationTests/tests/go.mod | 6 + integrationTests/tests/go.sum | 0 project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 +++ testHelpers/test_client_tsb.go | 151 ++ testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 ++++++++ tests/go.mod | 66 + tests/go.sum | 223 +++ tests/go.work | 5 + tests/go.work.sum | 163 ++ tests/path_config_test.go | 153 ++ tests/path_hsm_key_aes_test.go | 133 ++ tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 ++ tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 ++ tests/path_hsm_key_tdea_test.go | 136 ++ tests/path_hsm_key_using_type_name_test.go | 245 +++ tests/path_hsm_keys_rotation_test.go | 836 +++++++++ tests/path_hsm_keys_test.go | 312 ++++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++++ tests/path_hsm_operations_sign_test.go | 647 +++++++ tests/path_hsm_operations_unwrap_test.go | 675 +++++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++++++++ tests/path_hsm_operations_wrap_test.go | 242 +++ tests/path_hsm_requests_test.go | 299 +++ tests/path_mariadb_integration_test.go | 111 ++ 95 files changed, 23285 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-sse.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-sse.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 backend/path_mariadb_integration.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 docker-builder/alpine3/docker-compose-alpine3.yml create mode 100644 docker-builder/build-in-docker.sh create mode 100644 etc/example/mariaDb.cfg create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 go.work create mode 100644 go.work.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/mariadb_structs.go create mode 100644 helpers/structs.go create mode 100644 integrationTests/client/client.go create mode 100644 integrationTests/client/client_config.go create mode 100644 integrationTests/client/go.mod create mode 100644 integrationTests/client/go.sum create mode 100644 integrationTests/docker/docker-compose.yml create mode 100644 integrationTests/docker/docker-files/MariaDB_Dockerfile create mode 100644 integrationTests/docker/mysql-config/hashicorp.cnf create mode 100644 integrationTests/tests/a_enable_plugin_test.go create mode 100644 integrationTests/tests/b_config_plugin_test.go create mode 100644 integrationTests/tests/c_create_aes_key_test.go create mode 100644 integrationTests/tests/c_create_key_by_keyname_test.go create mode 100644 integrationTests/tests/c_create_rsa_key_test.go create mode 100644 integrationTests/tests/c_create_smart_rsa_key_test.go create mode 100644 integrationTests/tests/d_operations_on_key_test.go create mode 100644 integrationTests/tests/go.mod create mode 100644 integrationTests/tests/go.sum create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/go.work create mode 100644 tests/go.work.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go create mode 100644 tests/path_mariadb_integration_test.go diff --git a/.github/ISSUE_TEMPLATE/bug-report-sse.md b/.github/ISSUE_TEMPLATE/bug-report-sse.md new file mode 100644 index 0000000..40777e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-sse.md @@ -0,0 +1,49 @@ +--- +name: Bug report SSE +about: Create a report to help us improve +title: "[BUG] " +labels: '' +assignees: Peter-FNet + +--- + + + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment:** +* Vault Server Version (retrieve with `vault status`): +* Vault CLI Version (retrieve with `vault version`): +* Server Operating System/Architecture: + +Vault server configuration file(s): + +```hcl +# Paste your Vault config here. +# Be sure to scrub any sensitive values +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request-sse.md b/.github/ISSUE_TEMPLATE/feature-request-sse.md new file mode 100644 index 0000000..8264e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-sse.md @@ -0,0 +1,33 @@ +--- +name: Feature request SSE +about: Suggest an idea for this project +title: "[FEAT]" +labels: '' +assignees: Peter-FNet + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Explain any additional use-cases** +If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5375b60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +builds +vault +deploy +.gitlab-ci.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1e9dff6 --- /dev/null +++ b/Makefile @@ -0,0 +1,200 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` + +ifndef ARTIFACT_NAME +override ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +endif + +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + make release-alpine3 + echo "Finished!"; + +release-alpine3: + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-amd64 + make clean-docker-builder IMAGE=amd64/golang + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-i386 + make clean-docker-builder IMAGE=i386/golang + +clean-docker-builder: + @if [ "$$(docker images | grep '$(IMAGE)')" != "" ]; then \ + docker rmi -f $$(docker images | grep '$(IMAGE)' | awk '{ print $$3}') 2> /dev/null || true ; \ + fi; + docker volume prune -f + docker container prune -f + +run-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml up --build -d +clean-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml down --remove-orphans --rmi all + docker volume prune -f + docker container prune -f +integration-tests: + rm -fr integrationTests/docker/plugins/securosys-hsm + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -o integrationTests/docker/plugins/securosys-hsm cmd/securosys-hsm/main.go + make run-docker-test-container + + sleep 5 + go install github.com/jstemmer/go-junit-report/v2@latest + cd integrationTests/tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}integration_junit_report.xml -set-exit-code + + + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 15m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4828e0e --- /dev/null +++ b/Readme.md @@ -0,0 +1,1145 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Integrations](#integrations) + - [MariaDB](#mariadb) + - [Example usage](#mariadb-usage-example) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate and `keypath` with local PATH to the key. +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for Certificate authorization**: +```shell +$ vault write securosys-hsm/config +auth="CERT" +certpath="local_absolute_path_to_certificate.pem" +keypath="local_absolute_path_to_private.key" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=CERT' \ +--data-urlencode 'certpath=local_absolute_path_to_certificate.pem' \ +--data-urlencode 'keypath=local_absolute_path_to_private.pem' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Integrations +### MariaDB +Encryption on MariaDB can be enabled using existing plugin [Hashicorp Key Management Plugin](https://mariadb.com/kb/en/hashicorp-key-management-plugin/) +This integration stores generated secret in Secrets engine, encrypted by provided key. +**Supported Key Types**/**Algorithm** combinations: +| Key Type | Algorithm | +|----------|:-------------:| +| **RSA** |RSA_PADDING_OAEP_WITH_SHA512
RSA
RSA_PADDING_OAEP_WITH_SHA224
RSA_PADDING_OAEP_WITH_SHA256
RSA_PADDING_OAEP_WITH_SHA1
RSA_PADDING_OAEP
RSA_PADDING_OAEP_WITH_SHA384
RSA_NO_PADDING| +|**AES**|AES_GCM
AES_CTR
AES_ECB
AES_CBC_NO_PADDING
AES | +| **CHACHA20** | CHACHA20
CHACHA20_AEAD| +| **CAMELLIA** | CAMELLIA
CAMELLIA_CBC_NO_PADDING
CAMELLIA_ECB | +|**TDEA**| TDEA_CBC
TDEA_ECB
TDEA_CBC_NO_PADDING | + +>**Note** - Plugin supports **asynchronous decrypt operation** using key type **RSA** with **policy** with setup **ruleUse**. Using the key with policy will **stop** the decrypt operation and **wait for approvals** to be collected. + +There are a **serval steps** that is needed to be done before setup encryption on MariaDB +1) [Create / Register key](#manage-keys) into **Secrets Engine** +1) Generate new **secret** and encrypt it using stored key + ```shell + $ vault write securosys-hsm/integrations/mariadb/{secret-name} + keyName={key-name-from-secret-engine} + cipherAlgorithm={cipher-algorithm} + [additionalAuthenticationData={additional-authentication-data}] + [tagLength={tag-length}] + [password={password-for-a-key}] + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/integrations/mariadb/{secret-name} ' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName={key-name-from-secret-engine}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + >**Note** - Every request on this endpoint using same **key name** and **secret name** will **rotate secret** +1) The last step is add this configuration to **my.cfg** + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" + loose-hashicorp-key-management-token="{vault_access_token}" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + >**Note** - In **loose-hashicorp-key-management-vault-url** url need to ends with **&version=**. Plugin from **MariaDB** automatically add to end of url **number of secret version** +#### MariaDB usage example +This example using default configuration for **Hashicorp Vault dev server**. +| Data | Value | +|----------|:-------------:| +| **vault address** | https://localhost:8200 | +| **vault access token** | root | +1) **Create key** *MariaDBEncryptionKey* with key size *4096* with attributes at last "decrypt" equals *true* on HSM and store it as *mariadb_encryption_key* on **Secrets engine** + ```shell + $ vault write securosys-hsm/keys/rsa/mariadb_encryption_key + keyLabel="MariaDBEncryptionKey" + keySize=4096 + attributes='{"decrypt": true,"sign": false,"unwrap": false,"derive": true,"sensitive": true,"extractable": false,"modifiable": false,"copyable": false,"destroyable": true}' + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/keys/rsa/mariadb_encryption_key' \ + --header 'X-Vault-Token: root' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel=MariaDBEncryptionKey' \ + --data-urlencode 'keySize=4096' \ + --data-urlencode 'attributes={ + "decrypt": true, + "sign": false, + "unwrap": false, + "derive": true, + "sensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": false, + "copyable": false, + "destroyable": true + }' + ``` +1) Generate new **secret** called *mariadb_secret* and **encrypt it** using cipher algorithm *RSA* and stored key *mariadb_encryption_key* in **Secrets engine** + ```shell + $ vault write securosys-hsm/integrations/mariadb/mariadb_secret + keyName=mariadb_encryption_key + cipherAlgorithm=RSA + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret ' \ + --header 'X-Vault-Token: root' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName=mariadb_encryption_key' \ + --data-urlencode 'cipherAlgorithm=RSA' + ``` +3. Configure **MariaDB plugin** "Hashicorp Key Management" in database configuration in **my.cnf** + + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret/?key_name=mariadb_encryption_key&cipher_algorithm=RSA&version=" + loose-hashicorp-key-management-token="root" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + + + +--- +## Appendix +### Frequently Asked Questions +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..67cf38a --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,140 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + pathMariaDBIntegration(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..29a1fac --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,294 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "keypath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to key", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "KeyPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if keypath, ok := data.GetOk("keypath"); ok { + config.KeyPath = keypath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing keypath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.KeyPath) + + if err != nil { + return nil, fmt.Errorf("Keypath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..8281fe0 --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,452 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..32954d9 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string), map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy, map[string]string{}) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil, map[string]string{}) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString, nil) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..e24fe58 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} diff --git a/backend/path_mariadb_integration.go b/backend/path_mariadb_integration.go new file mode 100644 index 0000000..0101c1d --- /dev/null +++ b/backend/path_mariadb_integration.go @@ -0,0 +1,666 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for create Camellia Keys +func pathMariaDBIntegration(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "keyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsDelete, + }, + }, + HelpSynopsis: pathIntegrationMariaDBWriteHelpSynopsis, + HelpDescription: pathIntegrationMariaDBWriteHelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("version") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV1HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV1HelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV2HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV2HelpDescription, + }, + { + Pattern: "integrations/mariadb/?$", + Fields: map[string]*framework.FieldSchema{}, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsList, + }, + }, + HelpSynopsis: pathIntegrationMariaDBListHelpSynopsis, + HelpDescription: pathIntegrationMariaDBListHelpDescription, + }, + } +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "intergration/mariadb/") + if err != nil { + return nil, err + } + secrets := make([]string, 0, len(entries)) + secretsInfo := make(map[string]interface{}) + for _, name := range entries { + secrets = append(secrets, name) + secret, err := b.GetMariaDBSecret(ctx, req.Storage, name) + if err == nil { + secretsInfo[name] = map[string]interface{}{ + "KeyName": secret.KeyName, + "Version": secret.CurrentVersion, + "Created": secret.Created.Name, + "Updated": secret.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(secrets, secretsInfo), nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, errGet := b.GetMariaDBSecret(ctx, req.Storage, name) + if errGet != nil { + return nil, fmt.Errorf("error deleting mariadb secret: %w", errGet) + } + if storedSecret == nil { + return nil, fmt.Errorf("error deleting mariadb secret: secret with name %s not exists", d.Get("name").(string)) + + } + + err := req.Storage.Delete(ctx, "intergration/mariadb/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + rotate := false + if storedSecret != nil { + rotate = true + // return nil, fmt.Errorf("error secret with name: %s exists", name) + } else { + storedSecret = &helpers.MariaDBSecretEntry{} + + } + + keyName := d.Get("keyName").(string) + + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload := b64.StdEncoding.EncodeToString([]byte(helpers.GeneratePassword(32, false, false, false, true))) + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + sysView := b.System() + creator := helpers.Entity{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + creator.Aliases = entity.Aliases + creator.Id = entity.ID + creator.Name = entity.Name + creator.Date = time.Now().UTC() + + } else { + creator.Aliases = nil + creator.Id = "root" + creator.Name = "root" + creator.Date = time.Now().UTC() + + } + var messageAuthenticationCode *string = nil + if result["messageAuthenticationCode"] != nil { + temp := result["messageAuthenticationCode"].(string) + messageAuthenticationCode = &temp + } + var initializationVector *string = nil + if result["initializationVector"] != nil { + temp := result["initializationVector"].(string) + initializationVector = &temp + } + if !rotate { + storedSecret.InitSecret(keyName, keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + } else { + storedSecret.RotateSecret(keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + + } + if err := SetMariaDBSecret(ctx, req.Storage, name, storedSecret); err != nil { + return nil, err + } + + response := map[string]interface{}{} + now := storedSecret.GetActiveVersion().Created.Date + version := storedSecret.GetActiveVersion().Version + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + query := d.Get("query").(string) + if strings.HasPrefix(query, "?") { + query = query[1:] + } + params, err := url.ParseQuery(query) + + if query == "" { + str := "" + for key, value := range req.Data { + str = str + key + "=" + value.(string) + "&" + } + str = str[:len(str)-1] + params, err = url.ParseQuery(str) + } + + if err != nil { + return nil, err + } + name := d.Get("name").(string) + + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + if storedSecret == nil { + return nil, fmt.Errorf("error secret with name: %s not exists", name) + } + + version := "1" + if params.Has("version") { + if !strings.Contains(params.Get("version"), "?version=") { + version = storedSecret.CurrentVersion + } else { + parts := strings.Split(params.Get("version"), "?version=") + version = "v" + parts[1] + } + } else { + ver, ok := d.GetOk("version") + if !ok { + return nil, fmt.Errorf("error: missing version") + } + version = ver.(string) + } + + if !params.Has("key_name") { + return nil, fmt.Errorf("key_name query param not exists") + } + keyEntry, err := b.GetKey(ctx, req.Storage, params.Get("key_name")) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + keyName := params.Get("key_name") + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + + if !helpers.ContainsKey(storedSecret.Versions, version) { + return nil, fmt.Errorf("Secret version %s is not exists.", version) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload := storedSecret.GetVersion(version).EncryptedSecret + + if !params.Has("cipher_algorithm") { + return nil, fmt.Errorf("cipher_algorithm query param not exists") + } + + cipherAlgorithm := params.Get("cipher_algorithm") + if keyEntry.KeyTypeName != "aes256-gcm96" && cipherAlgorithm == "" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVectorString := "" + if params.Has("initialization_vector") { + initializationVectorString = params.Get("initialization_vector") + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + passwordString := "" + if params.Has("password") { + passwordString = params.Get("password") + } + tagLengthInt := -1 + if params.Has("tag_length") { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + } + if keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationDataString := "" + if params.Has("aad") { + additionalAuthenticationDataString = params.Get("aad") + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationDataString) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData (param aad) is not valid base64 string") + } + } + client, err := b.GetClient(ctx, req.Storage) + async := false + decrypted := "" + if len(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + async = true + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString, map[string]string{"integration": "MariaDB Encrypt"}) + if errEnc != nil { + return nil, errEnc + } + var resp *helpers.RequestResponse + resp, _, _ = client.GetRequest(requestId) + for resp.Status == "PENDING" { + time.Sleep(1000) + resp, _, _ = client.GetRequest(requestId) + } + if resp.Status != "EXECUTED" { + return nil, fmt.Errorf("error on async decrypt. Expected Status '%s' got '%s'", "EXECUTED", resp.Status) + } + decrypted = resp.Result + + } + } + } + if !async { + resultSync, errEnc := client.Decrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + decrypted = resultSync["payload"].(string) + } + + if cipherAlgorithm == "AES_ECB" || + cipherAlgorithm == "AES_CBC_NO_PADDING" || + cipherAlgorithm == "CAMELLIA_ECB" || + cipherAlgorithm == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + decoded, _ := base64.StdEncoding.DecodeString(decrypted) + response := map[string]interface{}{} + response["data"] = map[string]interface{}{"data": string(decoded)} + now := storedSecret.GetVersion(version).Created.Date + + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} + +// This function helps with saving key in Secrets Engine +func SetMariaDBSecret(ctx context.Context, s logical.Storage, name string, secretEntry *helpers.MariaDBSecretEntry) error { + entry, err := logical.StorageEntryJSON("intergration/mariadb/"+name, secretEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage secret") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetMariaDBSecret(ctx context.Context, s logical.Storage, name string) (*helpers.MariaDBSecretEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "intergration/mariadb/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var secret helpers.MariaDBSecretEntry + + if err := entry.DecodeJSON(&secret); err != nil { + return nil, err + } + return &secret, nil +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..b50c7e2 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1023 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + KeyPath: data["keypath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + ` + passwordString + ` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy, customMetaData map[string]string) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo, customMetaData) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString := "" + if len(keyToBeWrappedPasswordJson) > 2 { + keyToBeWrappedPasswordString = `"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString := "" + if len(wrapKeyPasswordJson) > 2 { + wrapKeyPasswordString = `"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + ` + keyToBeWrappedPasswordString + ` + "wrapKeyName": "` + wrapKeyName + `", + ` + wrapKeyPasswordString + ` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + ` + passwordString + ` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + ` + passwordString + ` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + ` + passwordString + ` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + ` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString := "" + if len(charsNewPasswordJson) > 2 { + newPasswordString = `"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + newPasswordString + ` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + passwordString + ` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + clientTLSCert, err := tls.LoadX509KeyPair(c.Auth.CertPath, c.Auth.KeyPath) + if err != nil { + log.Fatalf("Error loading certificate and key file: %v", err) + return nil, err, 0 + } + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + InsecureSkipVerify: true, + Certificates: []tls.Certificate{clientTLSCert}, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/docker-builder/alpine3/docker-compose-alpine3.yml b/docker-builder/alpine3/docker-compose-alpine3.yml new file mode 100644 index 0000000..1190d88 --- /dev/null +++ b/docker-builder/alpine3/docker-compose-alpine3.yml @@ -0,0 +1,56 @@ + version: "3.3" + services: + golang-builder-alpine3-amd64: + platform: linux/amd64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=amd64 + image: amd64/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-amd64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-i386: + platform: linux/i386 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=386 + image: i386/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-i386 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-arm64: + platform: linux/arm64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=arm64 + image: arm64v8/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-arm64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" \ No newline at end of file diff --git a/docker-builder/build-in-docker.sh b/docker-builder/build-in-docker.sh new file mode 100644 index 0000000..adc15b2 --- /dev/null +++ b/docker-builder/build-in-docker.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd .. +echo "Build ${ARTIFACT_NAME} in ${DOCKER_OS}_${DOCKER_ARCH}"; + cd /src + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; + cd builds; + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; + zip -9 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; + shasum -a 256 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; + cd ..; + rm builds/securosys-hsm; + rm builds/securosys-hsm_SHA256SUM; \ No newline at end of file diff --git a/etc/example/mariaDb.cfg b/etc/example/mariaDb.cfg new file mode 100644 index 0000000..298e73a --- /dev/null +++ b/etc/example/mariaDb.cfg @@ -0,0 +1,22 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" +loose-hashicorp-key-management-token="{vault_access_token}" +loose-hashicorp-key-management-check-kv-version="off" +#max timeout is 86400 seconds +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +#1 year in miliseconds +loose-hashicorp-key-management-cache-timeout=31556952000 +#1 year in miliseconds +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +#Example of innodb config +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = ON +innodb_encrypt_log = ON +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 \ No newline at end of file diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..8e00e02 --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,93 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..6eebb05 --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,29 @@ +# Securosys Hashicorp Vault Secrets Engine 1.1.0 +Issued: Dec, 6, 2023 +## Documentation Change +- Update Readme.md - added information about supporting and how to configure encryption on MariaDB +## Feature +- Added integration with MariaDB encryption +## Bugfix +- Fixed authentication with TSB using mTLS + +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build/ + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2d78c0c --- /dev/null +++ b/go.mod @@ -0,0 +1,80 @@ +module secretengine + +go 1.21 + +toolchain go1.21.2 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers + +replace securosys.ch/tests => ./tests + +replace securosys.ch/integration/client => ./integrationTests/client + +replace securosys.ch/integration/tests => ./integrationTests/tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/frankban/quicktest v1.14.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afae25d --- /dev/null +++ b/go.sum @@ -0,0 +1,254 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work new file mode 100644 index 0000000..ad36518 --- /dev/null +++ b/go.work @@ -0,0 +1,8 @@ +go 1.21 + +use ( + ./ + ./backend + ./integrationTests/client + ./integrationTests/tests +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..976ca94 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,164 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..bdc47e4 --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "math/rand" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} +func GetVersionNumber(version string) int { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + return versionInt +} +func GetVersionString(version string) string { + return strings.Replace(version, "v", "", 1) +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string, customMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + for key, value := range customMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + specialBytes = "!@#$%^&*()_+-=[]{}\\|;':\",.<>/?`~" + numBytes = "0123456789" + hexDecimalBytes = "0123456789ABCDEF" +) + +func GeneratePassword(length int, useLetters bool, useSpecial bool, useNum bool, useHexadecimal bool) string { + rand.Seed(time.Now().UnixNano()) + b := make([]byte, length) + arrayForRandom := make([]byte, 0) + if useLetters { + arrayForRandom = append(arrayForRandom, letterBytes...) + } + if useSpecial { + arrayForRandom = append(arrayForRandom, specialBytes...) + } + if useNum { + arrayForRandom = append(arrayForRandom, numBytes...) + } + if useHexadecimal { + arrayForRandom = append(arrayForRandom, hexDecimalBytes...) + + } + + for i := range b { + b[i] = arrayForRandom[rand.Intn(len(arrayForRandom))] + } + return string(b) +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/mariadb_structs.go b/helpers/mariadb_structs.go new file mode 100644 index 0000000..97210ac --- /dev/null +++ b/helpers/mariadb_structs.go @@ -0,0 +1,82 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// INTEGRATION MARIADB STRUCTS + +type MariaDBSecretEntry struct { + KeyName string `json:"keyName"` + Versions map[string]MariaDBSecretVersion `json:"secretVersions"` + CurrentVersion string `json:"defaultVersion"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +// Struct of keys stored inside the Vault +type MariaDBSecretVersion struct { + KeyVersion string `json:"keyVersion"` + EncryptedSecret string `json:"encryptedSecret"` + MessageAuthenticationCode *string `json:"messageAuthenticationCode"` + InitializationVector *string `json:"initializationVector"` + Version string `json:"version"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (s *MariaDBSecretEntry) InitSecret(keyName string, keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, creator Entity) { + s.CurrentVersion = "v1" + s.KeyName = keyName + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = "v1" + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = creator + secretVersion.Updated = creator + s.Created = creator + s.Updated = creator + s.Versions = make(map[string]MariaDBSecretVersion) + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) RotateSecret(keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, updater Entity) { + newSecretVersion := GetNewVersion(s.CurrentVersion) + s.CurrentVersion = newSecretVersion + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = newSecretVersion + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = updater + secretVersion.Updated = updater + s.Updated = updater + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) GetActiveVersion() MariaDBSecretVersion { + return s.Versions[s.CurrentVersion] +} +func (s *MariaDBSecretEntry) GetVersion(keyVersion string) MariaDBSecretVersion { + return s.Versions[keyVersion] +} + +// END INTEGRATION MARIADB STRUCTS diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9782f2d --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,316 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/integrationTests/client/client.go b/integrationTests/client/client.go new file mode 100644 index 0000000..70d4bee --- /dev/null +++ b/integrationTests/client/client.go @@ -0,0 +1,30 @@ +package integrationClient + +import ( + "fmt" + "log" + "os" + "time" + + "github.com/hashicorp/vault-client-go" +) + +func InitVaultClient() (*vault.Client){ + + // prepare a client with the given base address + client, err := vault.New( + vault.WithAddress(VaultConfig.Url+":"+fmt.Sprint(VaultConfig.Port)), + vault.WithRequestTimeout(30*time.Second), + ) + if err != nil { + log.Fatal(err) + os.Exit(1); + } + + // authenticate with a root token (insecure) + if err := client.SetToken(VaultConfig.RootToken); err != nil { + log.Fatal(err) + os.Exit(1); + } + return client; +} \ No newline at end of file diff --git a/integrationTests/client/client_config.go b/integrationTests/client/client_config.go new file mode 100644 index 0000000..148f2a9 --- /dev/null +++ b/integrationTests/client/client_config.go @@ -0,0 +1,15 @@ +package integrationClient + +type VaultClientConfig struct { + Port int + Url string + RootToken string + SecretsEnginePath string +} + +var VaultConfig VaultClientConfig=VaultClientConfig{ + Port: 8251, + Url: "http://127.0.0.1", + RootToken: "root", + SecretsEnginePath: "securosys-hsm", +} \ No newline at end of file diff --git a/integrationTests/client/go.mod b/integrationTests/client/go.mod new file mode 100644 index 0000000..02d12cd --- /dev/null +++ b/integrationTests/client/go.mod @@ -0,0 +1,24 @@ +module securosys.ch/integration/client + +go 1.21 + +toolchain go1.21.2 + +require github.com/hashicorp/vault-client-go v0.4.2 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stretchr/testify v1.8.2 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect +) diff --git a/integrationTests/client/go.sum b/integrationTests/client/go.sum new file mode 100644 index 0000000..3a52bd0 --- /dev/null +++ b/integrationTests/client/go.sum @@ -0,0 +1,58 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/vault-client-go v0.4.2 h1:XeUXb5jnDuCUhC8HRpkdGPLh1XtzXmiOnF0mXEbARxI= +github.com/hashicorp/vault-client-go v0.4.2/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integrationTests/docker/docker-compose.yml b/integrationTests/docker/docker-compose.yml new file mode 100644 index 0000000..1b00ff4 --- /dev/null +++ b/integrationTests/docker/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.0" +name: hashicorp-vault-test-containers +services: + hashicorp-vault-test: + image: hashicorp/vault:latest + container_name: "hashicorp-vault-test" + environment: + VAULT_DEV_ROOT_TOKEN_ID: root + VAULT_ADDR: 'https://0.0.0.0:8251' + VAULT_LOCAL_CONFIG: '{"listener": [{"tcp":{"address": "0.0.0.0:8251","tls_disable":"1"}}], "default_lease_ttl": "168h", "max_lease_ttl": "720h"}, "ui": true}' + volumes: + - ./plugins/:/vault/plugins + cap_add: + - IPC_LOCK + healthcheck: + retries: 5 + ports: + - "8251:8251" + privileged: true + command: server -dev -dev-root-token-id=root -dev-plugin-dir=/vault/plugins + networks: + - web + mariadb-test-integration: + build: + dockerfile: ./docker-files/MariaDB_Dockerfile + container_name: "mariadb-test-integration" + restart: always + environment: + MARIADB_ROOT_PASSWORD: example + volumes: + - ./mysql-config:/etc/mysql/conf.d + - ./db:/var/lib/mysql + networks: + - web + +networks: + web: + external: true + \ No newline at end of file diff --git a/integrationTests/docker/docker-files/MariaDB_Dockerfile b/integrationTests/docker/docker-files/MariaDB_Dockerfile new file mode 100644 index 0000000..7e5d37a --- /dev/null +++ b/integrationTests/docker/docker-files/MariaDB_Dockerfile @@ -0,0 +1,2 @@ +FROM mariadb:latest +RUN apt-get update && apt-get install -y mariadb-plugin-hashicorp-key-management diff --git a/integrationTests/docker/mysql-config/hashicorp.cnf b/integrationTests/docker/mysql-config/hashicorp.cnf new file mode 100644 index 0000000..d628bc7 --- /dev/null +++ b/integrationTests/docker/mysql-config/hashicorp.cnf @@ -0,0 +1,18 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="http://192.168.96.3:8251/v1/securosys-hsm/integrations/mariadb/test_async/?cipher_algorithm=RSA&key_name=rsa_with_policy&version=" +loose-hashicorp-key-management-token="root" +loose-hashicorp-key-management-check-kv-version="off" +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +loose-hashicorp-key-management-cache-timeout=31556952000 +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = OFF +innodb_encrypt_log = OFF +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 diff --git a/integrationTests/tests/a_enable_plugin_test.go b/integrationTests/tests/a_enable_plugin_test.go new file mode 100644 index 0000000..d16575a --- /dev/null +++ b/integrationTests/tests/a_enable_plugin_test.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "testing" + + "github.com/hashicorp/vault-client-go/schema" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestEnablePlugin(t *testing.T) { + + t.Run("A.1 Test Enable Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.System.MountsEnableSecretsEngine(ctx,integrationClient.VaultConfig.SecretsEnginePath,schema.MountsEnableSecretsEngineRequest{ + Type: "securosys-hsm", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/b_config_plugin_test.go b/integrationTests/tests/b_config_plugin_test.go new file mode 100644 index 0000000..d777766 --- /dev/null +++ b/integrationTests/tests/b_config_plugin_test.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfigPlugin(t *testing.T) { + + t.Run("B.1 Test Config Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/config",testHelpers.ConfigParams) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data["result"]==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s","null").Error()) + } + + if(!strings.Contains(resp.Data["result"].(string),"Connection successful:")){ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s",resp.Data["result"]).Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_aes_key_test.go b/integrationTests/tests/c_create_aes_key_test.go new file mode 100644 index 0000000..ccffd1b --- /dev/null +++ b/integrationTests/tests/c_create_aes_key_test.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateAESKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_aes"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_aes got %s","null").Error()) + } + }) + t.Run("C.3 Read AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["secretKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Key Secret got %s","null").Error()) + } + }) + t.Run("C.8 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_key_by_keyname_test.go b/integrationTests/tests/c_create_key_by_keyname_test.go new file mode 100644 index 0000000..285e47c --- /dev/null +++ b/integrationTests/tests/c_create_key_by_keyname_test.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateKeyByKeyNamePlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with label integrationTestKeyRSAName using name rsa-2048", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/type/rsa-2048/integration_test_key_rsa_name",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSAName", + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSAName"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSAName",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSAName_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test Remove Key RSA Key with name integrationTestKeyRSAName", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa_name",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_rsa_key_test.go b/integrationTests/tests/c_create_rsa_key_test.go new file mode 100644 index 0000000..90c1a10 --- /dev/null +++ b/integrationTests/tests/c_create_rsa_key_test.go @@ -0,0 +1,250 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["publicKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Public Key got %s","null").Error()) + } + if(resp.Data["privateKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Private Key got %s","null").Error()) + } + }) + t.Run("C.8 Update password RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/update-password",map[string]interface{}{ + "password":"", + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Test Remove Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_smart_rsa_key_test.go b/integrationTests/tests/c_create_smart_rsa_key_test.go new file mode 100644 index 0000000..dfdd792 --- /dev/null +++ b/integrationTests/tests/c_create_smart_rsa_key_test.go @@ -0,0 +1,255 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateSmartRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_smart_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_smart_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Block Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/block",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.8 UnBlock Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/unblock",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Update password Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/update-password",map[string]interface{}{ + "password":nil, + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/d_operations_on_key_test.go b/integrationTests/tests/d_operations_on_key_test.go new file mode 100644 index 0000000..8dc951b --- /dev/null +++ b/integrationTests/tests/d_operations_on_key_test.go @@ -0,0 +1,329 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestOperationsOnKeyPlugin(t *testing.T) { + + t.Run("D.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.2 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.3 Test Encrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.4 Test Encrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.5 Test Decrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.6 Test Decrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_key_aes",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.7 Test Sign using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + }) + t.Run("D.8 Test Verify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/verify/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "keyVersion":"v1", + "signatureAlgorithm":"SHA256_WITH_RSA", + "signature":resp.Data["signature"].(string), + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid got %s","null").Error()) + } + if(resp.Data["signatureValid"]==false){ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid %s got %s","true",resp.Data["signatureValid"]).Error()) + } + }) + t.Run("D.9 Test Modify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/modify",map[string]interface{}{ + "simplePolicy":`{"test":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnydX62tLYNF+Op1SRnX6avkkyQWlpYPagH85zxaGnMlZoMioqgjSOCuRvjaP7Y5noPMYayp3gJ2PwLXvw9+JlnL+iwklOcpONSa6gDoCDsk26DOoY0ELEPaGdW61mc2bj2hOQE0GEpPsRywJoRLS3B2e8bqRfAniAfGsUq3MK09iL5YOCuUCHCUiR9iZMSt0+Ek/kE4TrazbOCev1g6Ux2vOyTuQ6mF3wVuqwd8RhfvlNNKXbD2GD/jR3BwuhaodwzRPmDyDQPmEMwornxrMLavTcC+Igb4k5qol0Di6Oq8axpBvrH7KlxHT11Wd+ALKCsqoPSGxcIbd6TdN+ag9AQIDAQAB"}`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.11 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/go.mod b/integrationTests/tests/go.mod new file mode 100644 index 0000000..02bc999 --- /dev/null +++ b/integrationTests/tests/go.mod @@ -0,0 +1,6 @@ +module securosys.ch/integration/tests + +replace securosys.ch/integration/client => ./../client +replace securosys.ch/test-helpers => ./../../testHelpers + +go 1.19 diff --git a/integrationTests/tests/go.sum b/integrationTests/tests/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..0111058 --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.1.0 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..b55e030 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_API_URL", + "auth": "TOKEN", + "bearertoken": "TSB_BEARER_TOKEN", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/go.work b/tests/go.work new file mode 100644 index 0000000..7c33c4f --- /dev/null +++ b/tests/go.work @@ -0,0 +1,5 @@ +go 1.21 + +use ( + ./ +) \ No newline at end of file diff --git a/tests/go.work.sum b/tests/go.work.sum new file mode 100644 index 0000000..aff7933 --- /dev/null +++ b/tests/go.work.sum @@ -0,0 +1,163 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} diff --git a/tests/path_mariadb_integration_test.go b/tests/path_mariadb_integration_test.go new file mode 100644 index 0000000..b9b856e --- /dev/null +++ b/tests/path_mariadb_integration_test.go @@ -0,0 +1,111 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIntegrationMariaDB(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("A) add config", testEnv.AddConfig) + + t.Run("B) Test Creating RSA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + }) + t.Run("C)Add generate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("D)Read secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "integrations/mariadb/test/v1?key_name=custom_rsa_2048&cipher_algorithm=RSA", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("E) Rotate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("F) List secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "integrations/mariadb", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("G) Delete secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "integrations/mariadb/test", + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("H) Test Delete RSA key", func(t *testing.T) { + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + assert.NoError(t, err) + }) +} From b6a15aade7ab152f563466a9dc33123f521031d2 Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Wed, 31 Jan 2024 09:49:27 +0100 Subject: [PATCH 09/16] Release v.1.1.0 --- .github/ISSUE_TEMPLATE/bug-report-sse.md | 49 + .github/ISSUE_TEMPLATE/feature-request-sse.md | 33 + .gitignore | 4 + LICENSE | 201 ++ Makefile | 200 ++ Readme.md | 1145 ++++++++++++ backend/backend.go | 140 ++ backend/go.mod | 62 + backend/go.sum | 223 +++ backend/path_config.go | 294 +++ backend/path_help.go | 452 +++++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 +++ backend/path_hsm_key_bls.go | 259 +++ backend/path_hsm_key_camellia.go | 225 +++ backend/path_hsm_key_chacha20.go | 208 +++ backend/path_hsm_key_dsa.go | 273 +++ backend/path_hsm_key_ec.go | 270 +++ backend/path_hsm_key_ed.go | 271 +++ backend/path_hsm_key_import.go | 306 ++++ backend/path_hsm_key_rsa.go | 273 +++ backend/path_hsm_key_tdea.go | 208 +++ backend/path_hsm_key_with_name.go | 295 +++ backend/path_hsm_keys.go | 1359 ++++++++++++++ backend/path_hsm_operations.go | 1631 +++++++++++++++++ backend/path_hsm_requests.go | 298 +++ backend/path_mariadb_integration.go | 666 +++++++ client/client.go | 48 + client/client_tsb.go | 1023 +++++++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + .../alpine3/docker-compose-alpine3.yml | 56 + docker-builder/build-in-docker.sh | 12 + etc/example/mariaDb.cfg | 22 + etc/example/policy.json | 93 + etc/release_notes/Release_Notes.md | 29 + go.mod | 80 + go.sum | 254 +++ go.work | 8 + go.work.sum | 164 ++ helpers/consts.go | 53 + helpers/functions.go | 234 +++ helpers/go.mod | 57 + helpers/go.sum | 223 +++ helpers/mariadb_structs.go | 82 + helpers/structs.go | 316 ++++ integrationTests/client/client.go | 30 + integrationTests/client/client_config.go | 15 + integrationTests/client/go.mod | 24 + integrationTests/client/go.sum | 58 + integrationTests/docker/docker-compose.yml | 39 + .../docker/docker-files/MariaDB_Dockerfile | 2 + .../docker/mysql-config/hashicorp.cnf | 18 + .../tests/a_enable_plugin_test.go | 48 + .../tests/b_config_plugin_test.go | 55 + .../tests/c_create_aes_key_test.go | 234 +++ .../tests/c_create_key_by_keyname_test.go | 93 + .../tests/c_create_rsa_key_test.go | 250 +++ .../tests/c_create_smart_rsa_key_test.go | 255 +++ .../tests/d_operations_on_key_test.go | 329 ++++ integrationTests/tests/go.mod | 6 + integrationTests/tests/go.sum | 0 project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 +++ testHelpers/test_client_tsb.go | 151 ++ testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 ++++++++ tests/go.mod | 66 + tests/go.sum | 223 +++ tests/go.work | 5 + tests/go.work.sum | 163 ++ tests/path_config_test.go | 153 ++ tests/path_hsm_key_aes_test.go | 133 ++ tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 ++ tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 ++ tests/path_hsm_key_tdea_test.go | 136 ++ tests/path_hsm_key_using_type_name_test.go | 245 +++ tests/path_hsm_keys_rotation_test.go | 836 +++++++++ tests/path_hsm_keys_test.go | 312 ++++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++++ tests/path_hsm_operations_sign_test.go | 647 +++++++ tests/path_hsm_operations_unwrap_test.go | 675 +++++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++++++++ tests/path_hsm_operations_wrap_test.go | 242 +++ tests/path_hsm_requests_test.go | 299 +++ tests/path_mariadb_integration_test.go | 111 ++ 95 files changed, 23285 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-sse.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-sse.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 backend/path_mariadb_integration.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 docker-builder/alpine3/docker-compose-alpine3.yml create mode 100644 docker-builder/build-in-docker.sh create mode 100644 etc/example/mariaDb.cfg create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 go.work create mode 100644 go.work.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/mariadb_structs.go create mode 100644 helpers/structs.go create mode 100644 integrationTests/client/client.go create mode 100644 integrationTests/client/client_config.go create mode 100644 integrationTests/client/go.mod create mode 100644 integrationTests/client/go.sum create mode 100644 integrationTests/docker/docker-compose.yml create mode 100644 integrationTests/docker/docker-files/MariaDB_Dockerfile create mode 100644 integrationTests/docker/mysql-config/hashicorp.cnf create mode 100644 integrationTests/tests/a_enable_plugin_test.go create mode 100644 integrationTests/tests/b_config_plugin_test.go create mode 100644 integrationTests/tests/c_create_aes_key_test.go create mode 100644 integrationTests/tests/c_create_key_by_keyname_test.go create mode 100644 integrationTests/tests/c_create_rsa_key_test.go create mode 100644 integrationTests/tests/c_create_smart_rsa_key_test.go create mode 100644 integrationTests/tests/d_operations_on_key_test.go create mode 100644 integrationTests/tests/go.mod create mode 100644 integrationTests/tests/go.sum create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/go.work create mode 100644 tests/go.work.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go create mode 100644 tests/path_mariadb_integration_test.go diff --git a/.github/ISSUE_TEMPLATE/bug-report-sse.md b/.github/ISSUE_TEMPLATE/bug-report-sse.md new file mode 100644 index 0000000..40777e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-sse.md @@ -0,0 +1,49 @@ +--- +name: Bug report SSE +about: Create a report to help us improve +title: "[BUG] " +labels: '' +assignees: Peter-FNet + +--- + + + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment:** +* Vault Server Version (retrieve with `vault status`): +* Vault CLI Version (retrieve with `vault version`): +* Server Operating System/Architecture: + +Vault server configuration file(s): + +```hcl +# Paste your Vault config here. +# Be sure to scrub any sensitive values +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request-sse.md b/.github/ISSUE_TEMPLATE/feature-request-sse.md new file mode 100644 index 0000000..8264e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-sse.md @@ -0,0 +1,33 @@ +--- +name: Feature request SSE +about: Suggest an idea for this project +title: "[FEAT]" +labels: '' +assignees: Peter-FNet + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Explain any additional use-cases** +If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5375b60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +builds +vault +deploy +.gitlab-ci.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1e9dff6 --- /dev/null +++ b/Makefile @@ -0,0 +1,200 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` + +ifndef ARTIFACT_NAME +override ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +endif + +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + make release-alpine3 + echo "Finished!"; + +release-alpine3: + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-amd64 + make clean-docker-builder IMAGE=amd64/golang + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-i386 + make clean-docker-builder IMAGE=i386/golang + +clean-docker-builder: + @if [ "$$(docker images | grep '$(IMAGE)')" != "" ]; then \ + docker rmi -f $$(docker images | grep '$(IMAGE)' | awk '{ print $$3}') 2> /dev/null || true ; \ + fi; + docker volume prune -f + docker container prune -f + +run-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml up --build -d +clean-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml down --remove-orphans --rmi all + docker volume prune -f + docker container prune -f +integration-tests: + rm -fr integrationTests/docker/plugins/securosys-hsm + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -o integrationTests/docker/plugins/securosys-hsm cmd/securosys-hsm/main.go + make run-docker-test-container + + sleep 5 + go install github.com/jstemmer/go-junit-report/v2@latest + cd integrationTests/tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}integration_junit_report.xml -set-exit-code + + + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 15m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4828e0e --- /dev/null +++ b/Readme.md @@ -0,0 +1,1145 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Integrations](#integrations) + - [MariaDB](#mariadb) + - [Example usage](#mariadb-usage-example) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate and `keypath` with local PATH to the key. +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for Certificate authorization**: +```shell +$ vault write securosys-hsm/config +auth="CERT" +certpath="local_absolute_path_to_certificate.pem" +keypath="local_absolute_path_to_private.key" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=CERT' \ +--data-urlencode 'certpath=local_absolute_path_to_certificate.pem' \ +--data-urlencode 'keypath=local_absolute_path_to_private.pem' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Integrations +### MariaDB +Encryption on MariaDB can be enabled using existing plugin [Hashicorp Key Management Plugin](https://mariadb.com/kb/en/hashicorp-key-management-plugin/) +This integration stores generated secret in Secrets engine, encrypted by provided key. +**Supported Key Types**/**Algorithm** combinations: +| Key Type | Algorithm | +|----------|:-------------:| +| **RSA** |RSA_PADDING_OAEP_WITH_SHA512
RSA
RSA_PADDING_OAEP_WITH_SHA224
RSA_PADDING_OAEP_WITH_SHA256
RSA_PADDING_OAEP_WITH_SHA1
RSA_PADDING_OAEP
RSA_PADDING_OAEP_WITH_SHA384
RSA_NO_PADDING| +|**AES**|AES_GCM
AES_CTR
AES_ECB
AES_CBC_NO_PADDING
AES | +| **CHACHA20** | CHACHA20
CHACHA20_AEAD| +| **CAMELLIA** | CAMELLIA
CAMELLIA_CBC_NO_PADDING
CAMELLIA_ECB | +|**TDEA**| TDEA_CBC
TDEA_ECB
TDEA_CBC_NO_PADDING | + +>**Note** - Plugin supports **asynchronous decrypt operation** using key type **RSA** with **policy** with setup **ruleUse**. Using the key with policy will **stop** the decrypt operation and **wait for approvals** to be collected. + +There are a **serval steps** that is needed to be done before setup encryption on MariaDB +1) [Create / Register key](#manage-keys) into **Secrets Engine** +1) Generate new **secret** and encrypt it using stored key + ```shell + $ vault write securosys-hsm/integrations/mariadb/{secret-name} + keyName={key-name-from-secret-engine} + cipherAlgorithm={cipher-algorithm} + [additionalAuthenticationData={additional-authentication-data}] + [tagLength={tag-length}] + [password={password-for-a-key}] + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/integrations/mariadb/{secret-name} ' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName={key-name-from-secret-engine}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + >**Note** - Every request on this endpoint using same **key name** and **secret name** will **rotate secret** +1) The last step is add this configuration to **my.cfg** + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" + loose-hashicorp-key-management-token="{vault_access_token}" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + >**Note** - In **loose-hashicorp-key-management-vault-url** url need to ends with **&version=**. Plugin from **MariaDB** automatically add to end of url **number of secret version** +#### MariaDB usage example +This example using default configuration for **Hashicorp Vault dev server**. +| Data | Value | +|----------|:-------------:| +| **vault address** | https://localhost:8200 | +| **vault access token** | root | +1) **Create key** *MariaDBEncryptionKey* with key size *4096* with attributes at last "decrypt" equals *true* on HSM and store it as *mariadb_encryption_key* on **Secrets engine** + ```shell + $ vault write securosys-hsm/keys/rsa/mariadb_encryption_key + keyLabel="MariaDBEncryptionKey" + keySize=4096 + attributes='{"decrypt": true,"sign": false,"unwrap": false,"derive": true,"sensitive": true,"extractable": false,"modifiable": false,"copyable": false,"destroyable": true}' + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/keys/rsa/mariadb_encryption_key' \ + --header 'X-Vault-Token: root' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel=MariaDBEncryptionKey' \ + --data-urlencode 'keySize=4096' \ + --data-urlencode 'attributes={ + "decrypt": true, + "sign": false, + "unwrap": false, + "derive": true, + "sensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": false, + "copyable": false, + "destroyable": true + }' + ``` +1) Generate new **secret** called *mariadb_secret* and **encrypt it** using cipher algorithm *RSA* and stored key *mariadb_encryption_key* in **Secrets engine** + ```shell + $ vault write securosys-hsm/integrations/mariadb/mariadb_secret + keyName=mariadb_encryption_key + cipherAlgorithm=RSA + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret ' \ + --header 'X-Vault-Token: root' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName=mariadb_encryption_key' \ + --data-urlencode 'cipherAlgorithm=RSA' + ``` +3. Configure **MariaDB plugin** "Hashicorp Key Management" in database configuration in **my.cnf** + + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret/?key_name=mariadb_encryption_key&cipher_algorithm=RSA&version=" + loose-hashicorp-key-management-token="root" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + + + +--- +## Appendix +### Frequently Asked Questions +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..67cf38a --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,140 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + pathMariaDBIntegration(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..29a1fac --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,294 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "keypath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to key", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "KeyPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if keypath, ok := data.GetOk("keypath"); ok { + config.KeyPath = keypath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing keypath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.KeyPath) + + if err != nil { + return nil, fmt.Errorf("Keypath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..8281fe0 --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,452 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..32954d9 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string), map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy, map[string]string{}) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil, map[string]string{}) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString, nil) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..e24fe58 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} diff --git a/backend/path_mariadb_integration.go b/backend/path_mariadb_integration.go new file mode 100644 index 0000000..0101c1d --- /dev/null +++ b/backend/path_mariadb_integration.go @@ -0,0 +1,666 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for create Camellia Keys +func pathMariaDBIntegration(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "keyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsDelete, + }, + }, + HelpSynopsis: pathIntegrationMariaDBWriteHelpSynopsis, + HelpDescription: pathIntegrationMariaDBWriteHelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("version") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV1HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV1HelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV2HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV2HelpDescription, + }, + { + Pattern: "integrations/mariadb/?$", + Fields: map[string]*framework.FieldSchema{}, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsList, + }, + }, + HelpSynopsis: pathIntegrationMariaDBListHelpSynopsis, + HelpDescription: pathIntegrationMariaDBListHelpDescription, + }, + } +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "intergration/mariadb/") + if err != nil { + return nil, err + } + secrets := make([]string, 0, len(entries)) + secretsInfo := make(map[string]interface{}) + for _, name := range entries { + secrets = append(secrets, name) + secret, err := b.GetMariaDBSecret(ctx, req.Storage, name) + if err == nil { + secretsInfo[name] = map[string]interface{}{ + "KeyName": secret.KeyName, + "Version": secret.CurrentVersion, + "Created": secret.Created.Name, + "Updated": secret.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(secrets, secretsInfo), nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, errGet := b.GetMariaDBSecret(ctx, req.Storage, name) + if errGet != nil { + return nil, fmt.Errorf("error deleting mariadb secret: %w", errGet) + } + if storedSecret == nil { + return nil, fmt.Errorf("error deleting mariadb secret: secret with name %s not exists", d.Get("name").(string)) + + } + + err := req.Storage.Delete(ctx, "intergration/mariadb/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + rotate := false + if storedSecret != nil { + rotate = true + // return nil, fmt.Errorf("error secret with name: %s exists", name) + } else { + storedSecret = &helpers.MariaDBSecretEntry{} + + } + + keyName := d.Get("keyName").(string) + + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload := b64.StdEncoding.EncodeToString([]byte(helpers.GeneratePassword(32, false, false, false, true))) + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + sysView := b.System() + creator := helpers.Entity{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + creator.Aliases = entity.Aliases + creator.Id = entity.ID + creator.Name = entity.Name + creator.Date = time.Now().UTC() + + } else { + creator.Aliases = nil + creator.Id = "root" + creator.Name = "root" + creator.Date = time.Now().UTC() + + } + var messageAuthenticationCode *string = nil + if result["messageAuthenticationCode"] != nil { + temp := result["messageAuthenticationCode"].(string) + messageAuthenticationCode = &temp + } + var initializationVector *string = nil + if result["initializationVector"] != nil { + temp := result["initializationVector"].(string) + initializationVector = &temp + } + if !rotate { + storedSecret.InitSecret(keyName, keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + } else { + storedSecret.RotateSecret(keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + + } + if err := SetMariaDBSecret(ctx, req.Storage, name, storedSecret); err != nil { + return nil, err + } + + response := map[string]interface{}{} + now := storedSecret.GetActiveVersion().Created.Date + version := storedSecret.GetActiveVersion().Version + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + query := d.Get("query").(string) + if strings.HasPrefix(query, "?") { + query = query[1:] + } + params, err := url.ParseQuery(query) + + if query == "" { + str := "" + for key, value := range req.Data { + str = str + key + "=" + value.(string) + "&" + } + str = str[:len(str)-1] + params, err = url.ParseQuery(str) + } + + if err != nil { + return nil, err + } + name := d.Get("name").(string) + + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + if storedSecret == nil { + return nil, fmt.Errorf("error secret with name: %s not exists", name) + } + + version := "1" + if params.Has("version") { + if !strings.Contains(params.Get("version"), "?version=") { + version = storedSecret.CurrentVersion + } else { + parts := strings.Split(params.Get("version"), "?version=") + version = "v" + parts[1] + } + } else { + ver, ok := d.GetOk("version") + if !ok { + return nil, fmt.Errorf("error: missing version") + } + version = ver.(string) + } + + if !params.Has("key_name") { + return nil, fmt.Errorf("key_name query param not exists") + } + keyEntry, err := b.GetKey(ctx, req.Storage, params.Get("key_name")) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + keyName := params.Get("key_name") + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + + if !helpers.ContainsKey(storedSecret.Versions, version) { + return nil, fmt.Errorf("Secret version %s is not exists.", version) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload := storedSecret.GetVersion(version).EncryptedSecret + + if !params.Has("cipher_algorithm") { + return nil, fmt.Errorf("cipher_algorithm query param not exists") + } + + cipherAlgorithm := params.Get("cipher_algorithm") + if keyEntry.KeyTypeName != "aes256-gcm96" && cipherAlgorithm == "" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVectorString := "" + if params.Has("initialization_vector") { + initializationVectorString = params.Get("initialization_vector") + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + passwordString := "" + if params.Has("password") { + passwordString = params.Get("password") + } + tagLengthInt := -1 + if params.Has("tag_length") { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + } + if keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationDataString := "" + if params.Has("aad") { + additionalAuthenticationDataString = params.Get("aad") + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationDataString) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData (param aad) is not valid base64 string") + } + } + client, err := b.GetClient(ctx, req.Storage) + async := false + decrypted := "" + if len(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + async = true + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString, map[string]string{"integration": "MariaDB Encrypt"}) + if errEnc != nil { + return nil, errEnc + } + var resp *helpers.RequestResponse + resp, _, _ = client.GetRequest(requestId) + for resp.Status == "PENDING" { + time.Sleep(1000) + resp, _, _ = client.GetRequest(requestId) + } + if resp.Status != "EXECUTED" { + return nil, fmt.Errorf("error on async decrypt. Expected Status '%s' got '%s'", "EXECUTED", resp.Status) + } + decrypted = resp.Result + + } + } + } + if !async { + resultSync, errEnc := client.Decrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + decrypted = resultSync["payload"].(string) + } + + if cipherAlgorithm == "AES_ECB" || + cipherAlgorithm == "AES_CBC_NO_PADDING" || + cipherAlgorithm == "CAMELLIA_ECB" || + cipherAlgorithm == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + decoded, _ := base64.StdEncoding.DecodeString(decrypted) + response := map[string]interface{}{} + response["data"] = map[string]interface{}{"data": string(decoded)} + now := storedSecret.GetVersion(version).Created.Date + + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} + +// This function helps with saving key in Secrets Engine +func SetMariaDBSecret(ctx context.Context, s logical.Storage, name string, secretEntry *helpers.MariaDBSecretEntry) error { + entry, err := logical.StorageEntryJSON("intergration/mariadb/"+name, secretEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage secret") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetMariaDBSecret(ctx context.Context, s logical.Storage, name string) (*helpers.MariaDBSecretEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "intergration/mariadb/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var secret helpers.MariaDBSecretEntry + + if err := entry.DecodeJSON(&secret); err != nil { + return nil, err + } + return &secret, nil +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..b50c7e2 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1023 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + KeyPath: data["keypath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + ` + passwordString + ` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy, customMetaData map[string]string) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo, customMetaData) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString := "" + if len(keyToBeWrappedPasswordJson) > 2 { + keyToBeWrappedPasswordString = `"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString := "" + if len(wrapKeyPasswordJson) > 2 { + wrapKeyPasswordString = `"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + ` + keyToBeWrappedPasswordString + ` + "wrapKeyName": "` + wrapKeyName + `", + ` + wrapKeyPasswordString + ` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + ` + passwordString + ` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + ` + passwordString + ` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + ` + passwordString + ` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + ` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString := "" + if len(charsNewPasswordJson) > 2 { + newPasswordString = `"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + newPasswordString + ` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + passwordString + ` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + clientTLSCert, err := tls.LoadX509KeyPair(c.Auth.CertPath, c.Auth.KeyPath) + if err != nil { + log.Fatalf("Error loading certificate and key file: %v", err) + return nil, err, 0 + } + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + InsecureSkipVerify: true, + Certificates: []tls.Certificate{clientTLSCert}, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/docker-builder/alpine3/docker-compose-alpine3.yml b/docker-builder/alpine3/docker-compose-alpine3.yml new file mode 100644 index 0000000..1190d88 --- /dev/null +++ b/docker-builder/alpine3/docker-compose-alpine3.yml @@ -0,0 +1,56 @@ + version: "3.3" + services: + golang-builder-alpine3-amd64: + platform: linux/amd64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=amd64 + image: amd64/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-amd64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-i386: + platform: linux/i386 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=386 + image: i386/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-i386 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-arm64: + platform: linux/arm64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=arm64 + image: arm64v8/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-arm64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" \ No newline at end of file diff --git a/docker-builder/build-in-docker.sh b/docker-builder/build-in-docker.sh new file mode 100644 index 0000000..adc15b2 --- /dev/null +++ b/docker-builder/build-in-docker.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd .. +echo "Build ${ARTIFACT_NAME} in ${DOCKER_OS}_${DOCKER_ARCH}"; + cd /src + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; + cd builds; + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; + zip -9 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; + shasum -a 256 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; + cd ..; + rm builds/securosys-hsm; + rm builds/securosys-hsm_SHA256SUM; \ No newline at end of file diff --git a/etc/example/mariaDb.cfg b/etc/example/mariaDb.cfg new file mode 100644 index 0000000..298e73a --- /dev/null +++ b/etc/example/mariaDb.cfg @@ -0,0 +1,22 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" +loose-hashicorp-key-management-token="{vault_access_token}" +loose-hashicorp-key-management-check-kv-version="off" +#max timeout is 86400 seconds +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +#1 year in miliseconds +loose-hashicorp-key-management-cache-timeout=31556952000 +#1 year in miliseconds +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +#Example of innodb config +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = ON +innodb_encrypt_log = ON +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 \ No newline at end of file diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..8e00e02 --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,93 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..6eebb05 --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,29 @@ +# Securosys Hashicorp Vault Secrets Engine 1.1.0 +Issued: Dec, 6, 2023 +## Documentation Change +- Update Readme.md - added information about supporting and how to configure encryption on MariaDB +## Feature +- Added integration with MariaDB encryption +## Bugfix +- Fixed authentication with TSB using mTLS + +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build/ + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2d78c0c --- /dev/null +++ b/go.mod @@ -0,0 +1,80 @@ +module secretengine + +go 1.21 + +toolchain go1.21.2 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers + +replace securosys.ch/tests => ./tests + +replace securosys.ch/integration/client => ./integrationTests/client + +replace securosys.ch/integration/tests => ./integrationTests/tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/frankban/quicktest v1.14.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afae25d --- /dev/null +++ b/go.sum @@ -0,0 +1,254 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work new file mode 100644 index 0000000..ad36518 --- /dev/null +++ b/go.work @@ -0,0 +1,8 @@ +go 1.21 + +use ( + ./ + ./backend + ./integrationTests/client + ./integrationTests/tests +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..976ca94 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,164 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..bdc47e4 --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "math/rand" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} +func GetVersionNumber(version string) int { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + return versionInt +} +func GetVersionString(version string) string { + return strings.Replace(version, "v", "", 1) +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string, customMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + for key, value := range customMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + specialBytes = "!@#$%^&*()_+-=[]{}\\|;':\",.<>/?`~" + numBytes = "0123456789" + hexDecimalBytes = "0123456789ABCDEF" +) + +func GeneratePassword(length int, useLetters bool, useSpecial bool, useNum bool, useHexadecimal bool) string { + rand.Seed(time.Now().UnixNano()) + b := make([]byte, length) + arrayForRandom := make([]byte, 0) + if useLetters { + arrayForRandom = append(arrayForRandom, letterBytes...) + } + if useSpecial { + arrayForRandom = append(arrayForRandom, specialBytes...) + } + if useNum { + arrayForRandom = append(arrayForRandom, numBytes...) + } + if useHexadecimal { + arrayForRandom = append(arrayForRandom, hexDecimalBytes...) + + } + + for i := range b { + b[i] = arrayForRandom[rand.Intn(len(arrayForRandom))] + } + return string(b) +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/mariadb_structs.go b/helpers/mariadb_structs.go new file mode 100644 index 0000000..97210ac --- /dev/null +++ b/helpers/mariadb_structs.go @@ -0,0 +1,82 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// INTEGRATION MARIADB STRUCTS + +type MariaDBSecretEntry struct { + KeyName string `json:"keyName"` + Versions map[string]MariaDBSecretVersion `json:"secretVersions"` + CurrentVersion string `json:"defaultVersion"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +// Struct of keys stored inside the Vault +type MariaDBSecretVersion struct { + KeyVersion string `json:"keyVersion"` + EncryptedSecret string `json:"encryptedSecret"` + MessageAuthenticationCode *string `json:"messageAuthenticationCode"` + InitializationVector *string `json:"initializationVector"` + Version string `json:"version"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (s *MariaDBSecretEntry) InitSecret(keyName string, keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, creator Entity) { + s.CurrentVersion = "v1" + s.KeyName = keyName + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = "v1" + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = creator + secretVersion.Updated = creator + s.Created = creator + s.Updated = creator + s.Versions = make(map[string]MariaDBSecretVersion) + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) RotateSecret(keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, updater Entity) { + newSecretVersion := GetNewVersion(s.CurrentVersion) + s.CurrentVersion = newSecretVersion + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = newSecretVersion + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = updater + secretVersion.Updated = updater + s.Updated = updater + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) GetActiveVersion() MariaDBSecretVersion { + return s.Versions[s.CurrentVersion] +} +func (s *MariaDBSecretEntry) GetVersion(keyVersion string) MariaDBSecretVersion { + return s.Versions[keyVersion] +} + +// END INTEGRATION MARIADB STRUCTS diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9782f2d --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,316 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/integrationTests/client/client.go b/integrationTests/client/client.go new file mode 100644 index 0000000..70d4bee --- /dev/null +++ b/integrationTests/client/client.go @@ -0,0 +1,30 @@ +package integrationClient + +import ( + "fmt" + "log" + "os" + "time" + + "github.com/hashicorp/vault-client-go" +) + +func InitVaultClient() (*vault.Client){ + + // prepare a client with the given base address + client, err := vault.New( + vault.WithAddress(VaultConfig.Url+":"+fmt.Sprint(VaultConfig.Port)), + vault.WithRequestTimeout(30*time.Second), + ) + if err != nil { + log.Fatal(err) + os.Exit(1); + } + + // authenticate with a root token (insecure) + if err := client.SetToken(VaultConfig.RootToken); err != nil { + log.Fatal(err) + os.Exit(1); + } + return client; +} \ No newline at end of file diff --git a/integrationTests/client/client_config.go b/integrationTests/client/client_config.go new file mode 100644 index 0000000..148f2a9 --- /dev/null +++ b/integrationTests/client/client_config.go @@ -0,0 +1,15 @@ +package integrationClient + +type VaultClientConfig struct { + Port int + Url string + RootToken string + SecretsEnginePath string +} + +var VaultConfig VaultClientConfig=VaultClientConfig{ + Port: 8251, + Url: "http://127.0.0.1", + RootToken: "root", + SecretsEnginePath: "securosys-hsm", +} \ No newline at end of file diff --git a/integrationTests/client/go.mod b/integrationTests/client/go.mod new file mode 100644 index 0000000..02d12cd --- /dev/null +++ b/integrationTests/client/go.mod @@ -0,0 +1,24 @@ +module securosys.ch/integration/client + +go 1.21 + +toolchain go1.21.2 + +require github.com/hashicorp/vault-client-go v0.4.2 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stretchr/testify v1.8.2 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect +) diff --git a/integrationTests/client/go.sum b/integrationTests/client/go.sum new file mode 100644 index 0000000..3a52bd0 --- /dev/null +++ b/integrationTests/client/go.sum @@ -0,0 +1,58 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/vault-client-go v0.4.2 h1:XeUXb5jnDuCUhC8HRpkdGPLh1XtzXmiOnF0mXEbARxI= +github.com/hashicorp/vault-client-go v0.4.2/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integrationTests/docker/docker-compose.yml b/integrationTests/docker/docker-compose.yml new file mode 100644 index 0000000..1b00ff4 --- /dev/null +++ b/integrationTests/docker/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.0" +name: hashicorp-vault-test-containers +services: + hashicorp-vault-test: + image: hashicorp/vault:latest + container_name: "hashicorp-vault-test" + environment: + VAULT_DEV_ROOT_TOKEN_ID: root + VAULT_ADDR: 'https://0.0.0.0:8251' + VAULT_LOCAL_CONFIG: '{"listener": [{"tcp":{"address": "0.0.0.0:8251","tls_disable":"1"}}], "default_lease_ttl": "168h", "max_lease_ttl": "720h"}, "ui": true}' + volumes: + - ./plugins/:/vault/plugins + cap_add: + - IPC_LOCK + healthcheck: + retries: 5 + ports: + - "8251:8251" + privileged: true + command: server -dev -dev-root-token-id=root -dev-plugin-dir=/vault/plugins + networks: + - web + mariadb-test-integration: + build: + dockerfile: ./docker-files/MariaDB_Dockerfile + container_name: "mariadb-test-integration" + restart: always + environment: + MARIADB_ROOT_PASSWORD: example + volumes: + - ./mysql-config:/etc/mysql/conf.d + - ./db:/var/lib/mysql + networks: + - web + +networks: + web: + external: true + \ No newline at end of file diff --git a/integrationTests/docker/docker-files/MariaDB_Dockerfile b/integrationTests/docker/docker-files/MariaDB_Dockerfile new file mode 100644 index 0000000..7e5d37a --- /dev/null +++ b/integrationTests/docker/docker-files/MariaDB_Dockerfile @@ -0,0 +1,2 @@ +FROM mariadb:latest +RUN apt-get update && apt-get install -y mariadb-plugin-hashicorp-key-management diff --git a/integrationTests/docker/mysql-config/hashicorp.cnf b/integrationTests/docker/mysql-config/hashicorp.cnf new file mode 100644 index 0000000..d628bc7 --- /dev/null +++ b/integrationTests/docker/mysql-config/hashicorp.cnf @@ -0,0 +1,18 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="http://192.168.96.3:8251/v1/securosys-hsm/integrations/mariadb/test_async/?cipher_algorithm=RSA&key_name=rsa_with_policy&version=" +loose-hashicorp-key-management-token="root" +loose-hashicorp-key-management-check-kv-version="off" +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +loose-hashicorp-key-management-cache-timeout=31556952000 +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = OFF +innodb_encrypt_log = OFF +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 diff --git a/integrationTests/tests/a_enable_plugin_test.go b/integrationTests/tests/a_enable_plugin_test.go new file mode 100644 index 0000000..d16575a --- /dev/null +++ b/integrationTests/tests/a_enable_plugin_test.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "testing" + + "github.com/hashicorp/vault-client-go/schema" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestEnablePlugin(t *testing.T) { + + t.Run("A.1 Test Enable Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.System.MountsEnableSecretsEngine(ctx,integrationClient.VaultConfig.SecretsEnginePath,schema.MountsEnableSecretsEngineRequest{ + Type: "securosys-hsm", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/b_config_plugin_test.go b/integrationTests/tests/b_config_plugin_test.go new file mode 100644 index 0000000..d777766 --- /dev/null +++ b/integrationTests/tests/b_config_plugin_test.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfigPlugin(t *testing.T) { + + t.Run("B.1 Test Config Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/config",testHelpers.ConfigParams) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data["result"]==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s","null").Error()) + } + + if(!strings.Contains(resp.Data["result"].(string),"Connection successful:")){ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s",resp.Data["result"]).Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_aes_key_test.go b/integrationTests/tests/c_create_aes_key_test.go new file mode 100644 index 0000000..ccffd1b --- /dev/null +++ b/integrationTests/tests/c_create_aes_key_test.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateAESKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_aes"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_aes got %s","null").Error()) + } + }) + t.Run("C.3 Read AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["secretKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Key Secret got %s","null").Error()) + } + }) + t.Run("C.8 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_key_by_keyname_test.go b/integrationTests/tests/c_create_key_by_keyname_test.go new file mode 100644 index 0000000..285e47c --- /dev/null +++ b/integrationTests/tests/c_create_key_by_keyname_test.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateKeyByKeyNamePlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with label integrationTestKeyRSAName using name rsa-2048", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/type/rsa-2048/integration_test_key_rsa_name",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSAName", + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSAName"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSAName",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSAName_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test Remove Key RSA Key with name integrationTestKeyRSAName", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa_name",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_rsa_key_test.go b/integrationTests/tests/c_create_rsa_key_test.go new file mode 100644 index 0000000..90c1a10 --- /dev/null +++ b/integrationTests/tests/c_create_rsa_key_test.go @@ -0,0 +1,250 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["publicKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Public Key got %s","null").Error()) + } + if(resp.Data["privateKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Private Key got %s","null").Error()) + } + }) + t.Run("C.8 Update password RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/update-password",map[string]interface{}{ + "password":"", + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Test Remove Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_smart_rsa_key_test.go b/integrationTests/tests/c_create_smart_rsa_key_test.go new file mode 100644 index 0000000..dfdd792 --- /dev/null +++ b/integrationTests/tests/c_create_smart_rsa_key_test.go @@ -0,0 +1,255 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateSmartRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_smart_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_smart_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Block Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/block",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.8 UnBlock Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/unblock",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Update password Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/update-password",map[string]interface{}{ + "password":nil, + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/d_operations_on_key_test.go b/integrationTests/tests/d_operations_on_key_test.go new file mode 100644 index 0000000..8dc951b --- /dev/null +++ b/integrationTests/tests/d_operations_on_key_test.go @@ -0,0 +1,329 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestOperationsOnKeyPlugin(t *testing.T) { + + t.Run("D.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.2 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.3 Test Encrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.4 Test Encrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.5 Test Decrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.6 Test Decrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_key_aes",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.7 Test Sign using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + }) + t.Run("D.8 Test Verify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/verify/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "keyVersion":"v1", + "signatureAlgorithm":"SHA256_WITH_RSA", + "signature":resp.Data["signature"].(string), + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid got %s","null").Error()) + } + if(resp.Data["signatureValid"]==false){ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid %s got %s","true",resp.Data["signatureValid"]).Error()) + } + }) + t.Run("D.9 Test Modify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/modify",map[string]interface{}{ + "simplePolicy":`{"test":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnydX62tLYNF+Op1SRnX6avkkyQWlpYPagH85zxaGnMlZoMioqgjSOCuRvjaP7Y5noPMYayp3gJ2PwLXvw9+JlnL+iwklOcpONSa6gDoCDsk26DOoY0ELEPaGdW61mc2bj2hOQE0GEpPsRywJoRLS3B2e8bqRfAniAfGsUq3MK09iL5YOCuUCHCUiR9iZMSt0+Ek/kE4TrazbOCev1g6Ux2vOyTuQ6mF3wVuqwd8RhfvlNNKXbD2GD/jR3BwuhaodwzRPmDyDQPmEMwornxrMLavTcC+Igb4k5qol0Di6Oq8axpBvrH7KlxHT11Wd+ALKCsqoPSGxcIbd6TdN+ag9AQIDAQAB"}`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.11 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/go.mod b/integrationTests/tests/go.mod new file mode 100644 index 0000000..02bc999 --- /dev/null +++ b/integrationTests/tests/go.mod @@ -0,0 +1,6 @@ +module securosys.ch/integration/tests + +replace securosys.ch/integration/client => ./../client +replace securosys.ch/test-helpers => ./../../testHelpers + +go 1.19 diff --git a/integrationTests/tests/go.sum b/integrationTests/tests/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..0111058 --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.1.0 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..b55e030 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_API_URL", + "auth": "TOKEN", + "bearertoken": "TSB_BEARER_TOKEN", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/go.work b/tests/go.work new file mode 100644 index 0000000..7c33c4f --- /dev/null +++ b/tests/go.work @@ -0,0 +1,5 @@ +go 1.21 + +use ( + ./ +) \ No newline at end of file diff --git a/tests/go.work.sum b/tests/go.work.sum new file mode 100644 index 0000000..aff7933 --- /dev/null +++ b/tests/go.work.sum @@ -0,0 +1,163 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} diff --git a/tests/path_mariadb_integration_test.go b/tests/path_mariadb_integration_test.go new file mode 100644 index 0000000..b9b856e --- /dev/null +++ b/tests/path_mariadb_integration_test.go @@ -0,0 +1,111 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIntegrationMariaDB(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("A) add config", testEnv.AddConfig) + + t.Run("B) Test Creating RSA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + }) + t.Run("C)Add generate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("D)Read secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "integrations/mariadb/test/v1?key_name=custom_rsa_2048&cipher_algorithm=RSA", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("E) Rotate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("F) List secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "integrations/mariadb", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("G) Delete secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "integrations/mariadb/test", + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("H) Test Delete RSA key", func(t *testing.T) { + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + assert.NoError(t, err) + }) +} From cb9d95b5868ba93188488894e375f21b1017a047 Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Wed, 31 Jan 2024 10:04:55 +0100 Subject: [PATCH 10/16] Release v.1.1.0 --- .github/ISSUE_TEMPLATE/bug-report-sse.md | 49 + .github/ISSUE_TEMPLATE/feature-request-sse.md | 33 + .gitignore | 4 + LICENSE | 201 ++ Makefile | 201 ++ Readme.md | 1145 ++++++++++++ backend/backend.go | 140 ++ backend/go.mod | 62 + backend/go.sum | 223 +++ backend/path_config.go | 294 +++ backend/path_help.go | 452 +++++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 +++ backend/path_hsm_key_bls.go | 259 +++ backend/path_hsm_key_camellia.go | 225 +++ backend/path_hsm_key_chacha20.go | 208 +++ backend/path_hsm_key_dsa.go | 273 +++ backend/path_hsm_key_ec.go | 270 +++ backend/path_hsm_key_ed.go | 271 +++ backend/path_hsm_key_import.go | 306 ++++ backend/path_hsm_key_rsa.go | 273 +++ backend/path_hsm_key_tdea.go | 208 +++ backend/path_hsm_key_with_name.go | 295 +++ backend/path_hsm_keys.go | 1359 ++++++++++++++ backend/path_hsm_operations.go | 1631 +++++++++++++++++ backend/path_hsm_requests.go | 298 +++ backend/path_mariadb_integration.go | 666 +++++++ client/client.go | 48 + client/client_tsb.go | 1023 +++++++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + .../alpine3/docker-compose-alpine3.yml | 56 + docker-builder/build-in-docker.sh | 12 + etc/example/mariaDb.cfg | 22 + etc/example/policy.json | 93 + etc/release_notes/Release_Notes.md | 29 + go.mod | 80 + go.sum | 254 +++ go.work | 8 + go.work.sum | 164 ++ helpers/consts.go | 53 + helpers/functions.go | 234 +++ helpers/go.mod | 57 + helpers/go.sum | 223 +++ helpers/mariadb_structs.go | 82 + helpers/structs.go | 316 ++++ integrationTests/client/client.go | 30 + integrationTests/client/client_config.go | 15 + integrationTests/client/go.mod | 24 + integrationTests/client/go.sum | 58 + integrationTests/docker/docker-compose.yml | 39 + .../docker/docker-files/MariaDB_Dockerfile | 2 + .../docker/mysql-config/hashicorp.cnf | 18 + .../tests/a_enable_plugin_test.go | 48 + .../tests/b_config_plugin_test.go | 55 + .../tests/c_create_aes_key_test.go | 234 +++ .../tests/c_create_key_by_keyname_test.go | 93 + .../tests/c_create_rsa_key_test.go | 250 +++ .../tests/c_create_smart_rsa_key_test.go | 255 +++ .../tests/d_operations_on_key_test.go | 329 ++++ integrationTests/tests/go.mod | 6 + integrationTests/tests/go.sum | 0 project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 +++ testHelpers/test_client_tsb.go | 151 ++ testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 ++++++++ tests/go.mod | 66 + tests/go.sum | 223 +++ tests/go.work | 5 + tests/go.work.sum | 163 ++ tests/path_config_test.go | 153 ++ tests/path_hsm_key_aes_test.go | 133 ++ tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 ++ tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 ++ tests/path_hsm_key_tdea_test.go | 136 ++ tests/path_hsm_key_using_type_name_test.go | 245 +++ tests/path_hsm_keys_rotation_test.go | 836 +++++++++ tests/path_hsm_keys_test.go | 312 ++++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++++ tests/path_hsm_operations_sign_test.go | 647 +++++++ tests/path_hsm_operations_unwrap_test.go | 675 +++++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++++++++ tests/path_hsm_operations_wrap_test.go | 242 +++ tests/path_hsm_requests_test.go | 299 +++ tests/path_mariadb_integration_test.go | 111 ++ 95 files changed, 23286 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-sse.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-sse.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 backend/path_mariadb_integration.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 docker-builder/alpine3/docker-compose-alpine3.yml create mode 100644 docker-builder/build-in-docker.sh create mode 100644 etc/example/mariaDb.cfg create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 go.work create mode 100644 go.work.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/mariadb_structs.go create mode 100644 helpers/structs.go create mode 100644 integrationTests/client/client.go create mode 100644 integrationTests/client/client_config.go create mode 100644 integrationTests/client/go.mod create mode 100644 integrationTests/client/go.sum create mode 100644 integrationTests/docker/docker-compose.yml create mode 100644 integrationTests/docker/docker-files/MariaDB_Dockerfile create mode 100644 integrationTests/docker/mysql-config/hashicorp.cnf create mode 100644 integrationTests/tests/a_enable_plugin_test.go create mode 100644 integrationTests/tests/b_config_plugin_test.go create mode 100644 integrationTests/tests/c_create_aes_key_test.go create mode 100644 integrationTests/tests/c_create_key_by_keyname_test.go create mode 100644 integrationTests/tests/c_create_rsa_key_test.go create mode 100644 integrationTests/tests/c_create_smart_rsa_key_test.go create mode 100644 integrationTests/tests/d_operations_on_key_test.go create mode 100644 integrationTests/tests/go.mod create mode 100644 integrationTests/tests/go.sum create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/go.work create mode 100644 tests/go.work.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go create mode 100644 tests/path_mariadb_integration_test.go diff --git a/.github/ISSUE_TEMPLATE/bug-report-sse.md b/.github/ISSUE_TEMPLATE/bug-report-sse.md new file mode 100644 index 0000000..40777e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-sse.md @@ -0,0 +1,49 @@ +--- +name: Bug report SSE +about: Create a report to help us improve +title: "[BUG] " +labels: '' +assignees: Peter-FNet + +--- + + + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment:** +* Vault Server Version (retrieve with `vault status`): +* Vault CLI Version (retrieve with `vault version`): +* Server Operating System/Architecture: + +Vault server configuration file(s): + +```hcl +# Paste your Vault config here. +# Be sure to scrub any sensitive values +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request-sse.md b/.github/ISSUE_TEMPLATE/feature-request-sse.md new file mode 100644 index 0000000..8264e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-sse.md @@ -0,0 +1,33 @@ +--- +name: Feature request SSE +about: Suggest an idea for this project +title: "[FEAT]" +labels: '' +assignees: Peter-FNet + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Explain any additional use-cases** +If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5375b60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +builds +vault +deploy +.gitlab-ci.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a142d1d --- /dev/null +++ b/Makefile @@ -0,0 +1,201 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` + +ifndef ARTIFACT_NAME +override ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +endif + +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + make release-alpine3 + echo "Finished!"; + +release-alpine3: + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-amd64 + make clean-docker-builder IMAGE=amd64/golang + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-i386 + make clean-docker-builder IMAGE=i386/golang + +clean-docker-builder: + @if [ "$$(docker images | grep '$(IMAGE)')" != "" ]; then \ + docker rmi -f $$(docker images | grep '$(IMAGE)' | awk '{ print $$3}') 2> /dev/null || true ; \ + fi; + docker volume prune -f + docker container prune -f + docker network prune -f + +run-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml up --build -d +clean-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml down --remove-orphans --rmi all + docker volume prune -f + docker container prune -f +integration-tests: + rm -fr integrationTests/docker/plugins/securosys-hsm + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -o integrationTests/docker/plugins/securosys-hsm cmd/securosys-hsm/main.go + make run-docker-test-container + + sleep 5 + go install github.com/jstemmer/go-junit-report/v2@latest + cd integrationTests/tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}integration_junit_report.xml -set-exit-code + + + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 15m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4828e0e --- /dev/null +++ b/Readme.md @@ -0,0 +1,1145 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Integrations](#integrations) + - [MariaDB](#mariadb) + - [Example usage](#mariadb-usage-example) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate and `keypath` with local PATH to the key. +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for Certificate authorization**: +```shell +$ vault write securosys-hsm/config +auth="CERT" +certpath="local_absolute_path_to_certificate.pem" +keypath="local_absolute_path_to_private.key" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=CERT' \ +--data-urlencode 'certpath=local_absolute_path_to_certificate.pem' \ +--data-urlencode 'keypath=local_absolute_path_to_private.pem' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Integrations +### MariaDB +Encryption on MariaDB can be enabled using existing plugin [Hashicorp Key Management Plugin](https://mariadb.com/kb/en/hashicorp-key-management-plugin/) +This integration stores generated secret in Secrets engine, encrypted by provided key. +**Supported Key Types**/**Algorithm** combinations: +| Key Type | Algorithm | +|----------|:-------------:| +| **RSA** |RSA_PADDING_OAEP_WITH_SHA512
RSA
RSA_PADDING_OAEP_WITH_SHA224
RSA_PADDING_OAEP_WITH_SHA256
RSA_PADDING_OAEP_WITH_SHA1
RSA_PADDING_OAEP
RSA_PADDING_OAEP_WITH_SHA384
RSA_NO_PADDING| +|**AES**|AES_GCM
AES_CTR
AES_ECB
AES_CBC_NO_PADDING
AES | +| **CHACHA20** | CHACHA20
CHACHA20_AEAD| +| **CAMELLIA** | CAMELLIA
CAMELLIA_CBC_NO_PADDING
CAMELLIA_ECB | +|**TDEA**| TDEA_CBC
TDEA_ECB
TDEA_CBC_NO_PADDING | + +>**Note** - Plugin supports **asynchronous decrypt operation** using key type **RSA** with **policy** with setup **ruleUse**. Using the key with policy will **stop** the decrypt operation and **wait for approvals** to be collected. + +There are a **serval steps** that is needed to be done before setup encryption on MariaDB +1) [Create / Register key](#manage-keys) into **Secrets Engine** +1) Generate new **secret** and encrypt it using stored key + ```shell + $ vault write securosys-hsm/integrations/mariadb/{secret-name} + keyName={key-name-from-secret-engine} + cipherAlgorithm={cipher-algorithm} + [additionalAuthenticationData={additional-authentication-data}] + [tagLength={tag-length}] + [password={password-for-a-key}] + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/integrations/mariadb/{secret-name} ' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName={key-name-from-secret-engine}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + >**Note** - Every request on this endpoint using same **key name** and **secret name** will **rotate secret** +1) The last step is add this configuration to **my.cfg** + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" + loose-hashicorp-key-management-token="{vault_access_token}" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + >**Note** - In **loose-hashicorp-key-management-vault-url** url need to ends with **&version=**. Plugin from **MariaDB** automatically add to end of url **number of secret version** +#### MariaDB usage example +This example using default configuration for **Hashicorp Vault dev server**. +| Data | Value | +|----------|:-------------:| +| **vault address** | https://localhost:8200 | +| **vault access token** | root | +1) **Create key** *MariaDBEncryptionKey* with key size *4096* with attributes at last "decrypt" equals *true* on HSM and store it as *mariadb_encryption_key* on **Secrets engine** + ```shell + $ vault write securosys-hsm/keys/rsa/mariadb_encryption_key + keyLabel="MariaDBEncryptionKey" + keySize=4096 + attributes='{"decrypt": true,"sign": false,"unwrap": false,"derive": true,"sensitive": true,"extractable": false,"modifiable": false,"copyable": false,"destroyable": true}' + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/keys/rsa/mariadb_encryption_key' \ + --header 'X-Vault-Token: root' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel=MariaDBEncryptionKey' \ + --data-urlencode 'keySize=4096' \ + --data-urlencode 'attributes={ + "decrypt": true, + "sign": false, + "unwrap": false, + "derive": true, + "sensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": false, + "copyable": false, + "destroyable": true + }' + ``` +1) Generate new **secret** called *mariadb_secret* and **encrypt it** using cipher algorithm *RSA* and stored key *mariadb_encryption_key* in **Secrets engine** + ```shell + $ vault write securosys-hsm/integrations/mariadb/mariadb_secret + keyName=mariadb_encryption_key + cipherAlgorithm=RSA + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret ' \ + --header 'X-Vault-Token: root' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName=mariadb_encryption_key' \ + --data-urlencode 'cipherAlgorithm=RSA' + ``` +3. Configure **MariaDB plugin** "Hashicorp Key Management" in database configuration in **my.cnf** + + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret/?key_name=mariadb_encryption_key&cipher_algorithm=RSA&version=" + loose-hashicorp-key-management-token="root" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + + + +--- +## Appendix +### Frequently Asked Questions +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..67cf38a --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,140 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + pathMariaDBIntegration(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..29a1fac --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,294 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "keypath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to key", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "KeyPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if keypath, ok := data.GetOk("keypath"); ok { + config.KeyPath = keypath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing keypath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.KeyPath) + + if err != nil { + return nil, fmt.Errorf("Keypath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..8281fe0 --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,452 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..32954d9 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string), map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy, map[string]string{}) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil, map[string]string{}) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString, nil) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..e24fe58 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} diff --git a/backend/path_mariadb_integration.go b/backend/path_mariadb_integration.go new file mode 100644 index 0000000..0101c1d --- /dev/null +++ b/backend/path_mariadb_integration.go @@ -0,0 +1,666 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for create Camellia Keys +func pathMariaDBIntegration(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "keyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsDelete, + }, + }, + HelpSynopsis: pathIntegrationMariaDBWriteHelpSynopsis, + HelpDescription: pathIntegrationMariaDBWriteHelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("version") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV1HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV1HelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV2HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV2HelpDescription, + }, + { + Pattern: "integrations/mariadb/?$", + Fields: map[string]*framework.FieldSchema{}, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsList, + }, + }, + HelpSynopsis: pathIntegrationMariaDBListHelpSynopsis, + HelpDescription: pathIntegrationMariaDBListHelpDescription, + }, + } +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "intergration/mariadb/") + if err != nil { + return nil, err + } + secrets := make([]string, 0, len(entries)) + secretsInfo := make(map[string]interface{}) + for _, name := range entries { + secrets = append(secrets, name) + secret, err := b.GetMariaDBSecret(ctx, req.Storage, name) + if err == nil { + secretsInfo[name] = map[string]interface{}{ + "KeyName": secret.KeyName, + "Version": secret.CurrentVersion, + "Created": secret.Created.Name, + "Updated": secret.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(secrets, secretsInfo), nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, errGet := b.GetMariaDBSecret(ctx, req.Storage, name) + if errGet != nil { + return nil, fmt.Errorf("error deleting mariadb secret: %w", errGet) + } + if storedSecret == nil { + return nil, fmt.Errorf("error deleting mariadb secret: secret with name %s not exists", d.Get("name").(string)) + + } + + err := req.Storage.Delete(ctx, "intergration/mariadb/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + rotate := false + if storedSecret != nil { + rotate = true + // return nil, fmt.Errorf("error secret with name: %s exists", name) + } else { + storedSecret = &helpers.MariaDBSecretEntry{} + + } + + keyName := d.Get("keyName").(string) + + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload := b64.StdEncoding.EncodeToString([]byte(helpers.GeneratePassword(32, false, false, false, true))) + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + sysView := b.System() + creator := helpers.Entity{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + creator.Aliases = entity.Aliases + creator.Id = entity.ID + creator.Name = entity.Name + creator.Date = time.Now().UTC() + + } else { + creator.Aliases = nil + creator.Id = "root" + creator.Name = "root" + creator.Date = time.Now().UTC() + + } + var messageAuthenticationCode *string = nil + if result["messageAuthenticationCode"] != nil { + temp := result["messageAuthenticationCode"].(string) + messageAuthenticationCode = &temp + } + var initializationVector *string = nil + if result["initializationVector"] != nil { + temp := result["initializationVector"].(string) + initializationVector = &temp + } + if !rotate { + storedSecret.InitSecret(keyName, keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + } else { + storedSecret.RotateSecret(keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + + } + if err := SetMariaDBSecret(ctx, req.Storage, name, storedSecret); err != nil { + return nil, err + } + + response := map[string]interface{}{} + now := storedSecret.GetActiveVersion().Created.Date + version := storedSecret.GetActiveVersion().Version + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + query := d.Get("query").(string) + if strings.HasPrefix(query, "?") { + query = query[1:] + } + params, err := url.ParseQuery(query) + + if query == "" { + str := "" + for key, value := range req.Data { + str = str + key + "=" + value.(string) + "&" + } + str = str[:len(str)-1] + params, err = url.ParseQuery(str) + } + + if err != nil { + return nil, err + } + name := d.Get("name").(string) + + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + if storedSecret == nil { + return nil, fmt.Errorf("error secret with name: %s not exists", name) + } + + version := "1" + if params.Has("version") { + if !strings.Contains(params.Get("version"), "?version=") { + version = storedSecret.CurrentVersion + } else { + parts := strings.Split(params.Get("version"), "?version=") + version = "v" + parts[1] + } + } else { + ver, ok := d.GetOk("version") + if !ok { + return nil, fmt.Errorf("error: missing version") + } + version = ver.(string) + } + + if !params.Has("key_name") { + return nil, fmt.Errorf("key_name query param not exists") + } + keyEntry, err := b.GetKey(ctx, req.Storage, params.Get("key_name")) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + keyName := params.Get("key_name") + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + + if !helpers.ContainsKey(storedSecret.Versions, version) { + return nil, fmt.Errorf("Secret version %s is not exists.", version) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload := storedSecret.GetVersion(version).EncryptedSecret + + if !params.Has("cipher_algorithm") { + return nil, fmt.Errorf("cipher_algorithm query param not exists") + } + + cipherAlgorithm := params.Get("cipher_algorithm") + if keyEntry.KeyTypeName != "aes256-gcm96" && cipherAlgorithm == "" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVectorString := "" + if params.Has("initialization_vector") { + initializationVectorString = params.Get("initialization_vector") + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + passwordString := "" + if params.Has("password") { + passwordString = params.Get("password") + } + tagLengthInt := -1 + if params.Has("tag_length") { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + } + if keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationDataString := "" + if params.Has("aad") { + additionalAuthenticationDataString = params.Get("aad") + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationDataString) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData (param aad) is not valid base64 string") + } + } + client, err := b.GetClient(ctx, req.Storage) + async := false + decrypted := "" + if len(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + async = true + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString, map[string]string{"integration": "MariaDB Encrypt"}) + if errEnc != nil { + return nil, errEnc + } + var resp *helpers.RequestResponse + resp, _, _ = client.GetRequest(requestId) + for resp.Status == "PENDING" { + time.Sleep(1000) + resp, _, _ = client.GetRequest(requestId) + } + if resp.Status != "EXECUTED" { + return nil, fmt.Errorf("error on async decrypt. Expected Status '%s' got '%s'", "EXECUTED", resp.Status) + } + decrypted = resp.Result + + } + } + } + if !async { + resultSync, errEnc := client.Decrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + decrypted = resultSync["payload"].(string) + } + + if cipherAlgorithm == "AES_ECB" || + cipherAlgorithm == "AES_CBC_NO_PADDING" || + cipherAlgorithm == "CAMELLIA_ECB" || + cipherAlgorithm == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + decoded, _ := base64.StdEncoding.DecodeString(decrypted) + response := map[string]interface{}{} + response["data"] = map[string]interface{}{"data": string(decoded)} + now := storedSecret.GetVersion(version).Created.Date + + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} + +// This function helps with saving key in Secrets Engine +func SetMariaDBSecret(ctx context.Context, s logical.Storage, name string, secretEntry *helpers.MariaDBSecretEntry) error { + entry, err := logical.StorageEntryJSON("intergration/mariadb/"+name, secretEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage secret") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetMariaDBSecret(ctx context.Context, s logical.Storage, name string) (*helpers.MariaDBSecretEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "intergration/mariadb/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var secret helpers.MariaDBSecretEntry + + if err := entry.DecodeJSON(&secret); err != nil { + return nil, err + } + return &secret, nil +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..b50c7e2 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1023 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + KeyPath: data["keypath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + ` + passwordString + ` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy, customMetaData map[string]string) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo, customMetaData) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString := "" + if len(keyToBeWrappedPasswordJson) > 2 { + keyToBeWrappedPasswordString = `"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString := "" + if len(wrapKeyPasswordJson) > 2 { + wrapKeyPasswordString = `"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + ` + keyToBeWrappedPasswordString + ` + "wrapKeyName": "` + wrapKeyName + `", + ` + wrapKeyPasswordString + ` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + ` + passwordString + ` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + ` + passwordString + ` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + ` + passwordString + ` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + ` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString := "" + if len(charsNewPasswordJson) > 2 { + newPasswordString = `"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + newPasswordString + ` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + passwordString + ` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + clientTLSCert, err := tls.LoadX509KeyPair(c.Auth.CertPath, c.Auth.KeyPath) + if err != nil { + log.Fatalf("Error loading certificate and key file: %v", err) + return nil, err, 0 + } + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + InsecureSkipVerify: true, + Certificates: []tls.Certificate{clientTLSCert}, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/docker-builder/alpine3/docker-compose-alpine3.yml b/docker-builder/alpine3/docker-compose-alpine3.yml new file mode 100644 index 0000000..1190d88 --- /dev/null +++ b/docker-builder/alpine3/docker-compose-alpine3.yml @@ -0,0 +1,56 @@ + version: "3.3" + services: + golang-builder-alpine3-amd64: + platform: linux/amd64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=amd64 + image: amd64/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-amd64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-i386: + platform: linux/i386 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=386 + image: i386/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-i386 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-arm64: + platform: linux/arm64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=arm64 + image: arm64v8/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-arm64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" \ No newline at end of file diff --git a/docker-builder/build-in-docker.sh b/docker-builder/build-in-docker.sh new file mode 100644 index 0000000..adc15b2 --- /dev/null +++ b/docker-builder/build-in-docker.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd .. +echo "Build ${ARTIFACT_NAME} in ${DOCKER_OS}_${DOCKER_ARCH}"; + cd /src + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; + cd builds; + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; + zip -9 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; + shasum -a 256 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; + cd ..; + rm builds/securosys-hsm; + rm builds/securosys-hsm_SHA256SUM; \ No newline at end of file diff --git a/etc/example/mariaDb.cfg b/etc/example/mariaDb.cfg new file mode 100644 index 0000000..298e73a --- /dev/null +++ b/etc/example/mariaDb.cfg @@ -0,0 +1,22 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" +loose-hashicorp-key-management-token="{vault_access_token}" +loose-hashicorp-key-management-check-kv-version="off" +#max timeout is 86400 seconds +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +#1 year in miliseconds +loose-hashicorp-key-management-cache-timeout=31556952000 +#1 year in miliseconds +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +#Example of innodb config +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = ON +innodb_encrypt_log = ON +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 \ No newline at end of file diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..8e00e02 --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,93 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..6eebb05 --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,29 @@ +# Securosys Hashicorp Vault Secrets Engine 1.1.0 +Issued: Dec, 6, 2023 +## Documentation Change +- Update Readme.md - added information about supporting and how to configure encryption on MariaDB +## Feature +- Added integration with MariaDB encryption +## Bugfix +- Fixed authentication with TSB using mTLS + +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build/ + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2d78c0c --- /dev/null +++ b/go.mod @@ -0,0 +1,80 @@ +module secretengine + +go 1.21 + +toolchain go1.21.2 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers + +replace securosys.ch/tests => ./tests + +replace securosys.ch/integration/client => ./integrationTests/client + +replace securosys.ch/integration/tests => ./integrationTests/tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/frankban/quicktest v1.14.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afae25d --- /dev/null +++ b/go.sum @@ -0,0 +1,254 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work new file mode 100644 index 0000000..ad36518 --- /dev/null +++ b/go.work @@ -0,0 +1,8 @@ +go 1.21 + +use ( + ./ + ./backend + ./integrationTests/client + ./integrationTests/tests +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..976ca94 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,164 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..bdc47e4 --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "math/rand" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} +func GetVersionNumber(version string) int { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + return versionInt +} +func GetVersionString(version string) string { + return strings.Replace(version, "v", "", 1) +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string, customMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + for key, value := range customMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + specialBytes = "!@#$%^&*()_+-=[]{}\\|;':\",.<>/?`~" + numBytes = "0123456789" + hexDecimalBytes = "0123456789ABCDEF" +) + +func GeneratePassword(length int, useLetters bool, useSpecial bool, useNum bool, useHexadecimal bool) string { + rand.Seed(time.Now().UnixNano()) + b := make([]byte, length) + arrayForRandom := make([]byte, 0) + if useLetters { + arrayForRandom = append(arrayForRandom, letterBytes...) + } + if useSpecial { + arrayForRandom = append(arrayForRandom, specialBytes...) + } + if useNum { + arrayForRandom = append(arrayForRandom, numBytes...) + } + if useHexadecimal { + arrayForRandom = append(arrayForRandom, hexDecimalBytes...) + + } + + for i := range b { + b[i] = arrayForRandom[rand.Intn(len(arrayForRandom))] + } + return string(b) +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/mariadb_structs.go b/helpers/mariadb_structs.go new file mode 100644 index 0000000..97210ac --- /dev/null +++ b/helpers/mariadb_structs.go @@ -0,0 +1,82 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// INTEGRATION MARIADB STRUCTS + +type MariaDBSecretEntry struct { + KeyName string `json:"keyName"` + Versions map[string]MariaDBSecretVersion `json:"secretVersions"` + CurrentVersion string `json:"defaultVersion"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +// Struct of keys stored inside the Vault +type MariaDBSecretVersion struct { + KeyVersion string `json:"keyVersion"` + EncryptedSecret string `json:"encryptedSecret"` + MessageAuthenticationCode *string `json:"messageAuthenticationCode"` + InitializationVector *string `json:"initializationVector"` + Version string `json:"version"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (s *MariaDBSecretEntry) InitSecret(keyName string, keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, creator Entity) { + s.CurrentVersion = "v1" + s.KeyName = keyName + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = "v1" + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = creator + secretVersion.Updated = creator + s.Created = creator + s.Updated = creator + s.Versions = make(map[string]MariaDBSecretVersion) + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) RotateSecret(keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, updater Entity) { + newSecretVersion := GetNewVersion(s.CurrentVersion) + s.CurrentVersion = newSecretVersion + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = newSecretVersion + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = updater + secretVersion.Updated = updater + s.Updated = updater + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) GetActiveVersion() MariaDBSecretVersion { + return s.Versions[s.CurrentVersion] +} +func (s *MariaDBSecretEntry) GetVersion(keyVersion string) MariaDBSecretVersion { + return s.Versions[keyVersion] +} + +// END INTEGRATION MARIADB STRUCTS diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9782f2d --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,316 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/integrationTests/client/client.go b/integrationTests/client/client.go new file mode 100644 index 0000000..70d4bee --- /dev/null +++ b/integrationTests/client/client.go @@ -0,0 +1,30 @@ +package integrationClient + +import ( + "fmt" + "log" + "os" + "time" + + "github.com/hashicorp/vault-client-go" +) + +func InitVaultClient() (*vault.Client){ + + // prepare a client with the given base address + client, err := vault.New( + vault.WithAddress(VaultConfig.Url+":"+fmt.Sprint(VaultConfig.Port)), + vault.WithRequestTimeout(30*time.Second), + ) + if err != nil { + log.Fatal(err) + os.Exit(1); + } + + // authenticate with a root token (insecure) + if err := client.SetToken(VaultConfig.RootToken); err != nil { + log.Fatal(err) + os.Exit(1); + } + return client; +} \ No newline at end of file diff --git a/integrationTests/client/client_config.go b/integrationTests/client/client_config.go new file mode 100644 index 0000000..148f2a9 --- /dev/null +++ b/integrationTests/client/client_config.go @@ -0,0 +1,15 @@ +package integrationClient + +type VaultClientConfig struct { + Port int + Url string + RootToken string + SecretsEnginePath string +} + +var VaultConfig VaultClientConfig=VaultClientConfig{ + Port: 8251, + Url: "http://127.0.0.1", + RootToken: "root", + SecretsEnginePath: "securosys-hsm", +} \ No newline at end of file diff --git a/integrationTests/client/go.mod b/integrationTests/client/go.mod new file mode 100644 index 0000000..02d12cd --- /dev/null +++ b/integrationTests/client/go.mod @@ -0,0 +1,24 @@ +module securosys.ch/integration/client + +go 1.21 + +toolchain go1.21.2 + +require github.com/hashicorp/vault-client-go v0.4.2 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stretchr/testify v1.8.2 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect +) diff --git a/integrationTests/client/go.sum b/integrationTests/client/go.sum new file mode 100644 index 0000000..3a52bd0 --- /dev/null +++ b/integrationTests/client/go.sum @@ -0,0 +1,58 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/vault-client-go v0.4.2 h1:XeUXb5jnDuCUhC8HRpkdGPLh1XtzXmiOnF0mXEbARxI= +github.com/hashicorp/vault-client-go v0.4.2/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integrationTests/docker/docker-compose.yml b/integrationTests/docker/docker-compose.yml new file mode 100644 index 0000000..1b00ff4 --- /dev/null +++ b/integrationTests/docker/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.0" +name: hashicorp-vault-test-containers +services: + hashicorp-vault-test: + image: hashicorp/vault:latest + container_name: "hashicorp-vault-test" + environment: + VAULT_DEV_ROOT_TOKEN_ID: root + VAULT_ADDR: 'https://0.0.0.0:8251' + VAULT_LOCAL_CONFIG: '{"listener": [{"tcp":{"address": "0.0.0.0:8251","tls_disable":"1"}}], "default_lease_ttl": "168h", "max_lease_ttl": "720h"}, "ui": true}' + volumes: + - ./plugins/:/vault/plugins + cap_add: + - IPC_LOCK + healthcheck: + retries: 5 + ports: + - "8251:8251" + privileged: true + command: server -dev -dev-root-token-id=root -dev-plugin-dir=/vault/plugins + networks: + - web + mariadb-test-integration: + build: + dockerfile: ./docker-files/MariaDB_Dockerfile + container_name: "mariadb-test-integration" + restart: always + environment: + MARIADB_ROOT_PASSWORD: example + volumes: + - ./mysql-config:/etc/mysql/conf.d + - ./db:/var/lib/mysql + networks: + - web + +networks: + web: + external: true + \ No newline at end of file diff --git a/integrationTests/docker/docker-files/MariaDB_Dockerfile b/integrationTests/docker/docker-files/MariaDB_Dockerfile new file mode 100644 index 0000000..7e5d37a --- /dev/null +++ b/integrationTests/docker/docker-files/MariaDB_Dockerfile @@ -0,0 +1,2 @@ +FROM mariadb:latest +RUN apt-get update && apt-get install -y mariadb-plugin-hashicorp-key-management diff --git a/integrationTests/docker/mysql-config/hashicorp.cnf b/integrationTests/docker/mysql-config/hashicorp.cnf new file mode 100644 index 0000000..d628bc7 --- /dev/null +++ b/integrationTests/docker/mysql-config/hashicorp.cnf @@ -0,0 +1,18 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="http://192.168.96.3:8251/v1/securosys-hsm/integrations/mariadb/test_async/?cipher_algorithm=RSA&key_name=rsa_with_policy&version=" +loose-hashicorp-key-management-token="root" +loose-hashicorp-key-management-check-kv-version="off" +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +loose-hashicorp-key-management-cache-timeout=31556952000 +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = OFF +innodb_encrypt_log = OFF +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 diff --git a/integrationTests/tests/a_enable_plugin_test.go b/integrationTests/tests/a_enable_plugin_test.go new file mode 100644 index 0000000..d16575a --- /dev/null +++ b/integrationTests/tests/a_enable_plugin_test.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "testing" + + "github.com/hashicorp/vault-client-go/schema" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestEnablePlugin(t *testing.T) { + + t.Run("A.1 Test Enable Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.System.MountsEnableSecretsEngine(ctx,integrationClient.VaultConfig.SecretsEnginePath,schema.MountsEnableSecretsEngineRequest{ + Type: "securosys-hsm", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/b_config_plugin_test.go b/integrationTests/tests/b_config_plugin_test.go new file mode 100644 index 0000000..d777766 --- /dev/null +++ b/integrationTests/tests/b_config_plugin_test.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfigPlugin(t *testing.T) { + + t.Run("B.1 Test Config Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/config",testHelpers.ConfigParams) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data["result"]==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s","null").Error()) + } + + if(!strings.Contains(resp.Data["result"].(string),"Connection successful:")){ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s",resp.Data["result"]).Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_aes_key_test.go b/integrationTests/tests/c_create_aes_key_test.go new file mode 100644 index 0000000..ccffd1b --- /dev/null +++ b/integrationTests/tests/c_create_aes_key_test.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateAESKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_aes"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_aes got %s","null").Error()) + } + }) + t.Run("C.3 Read AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["secretKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Key Secret got %s","null").Error()) + } + }) + t.Run("C.8 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_key_by_keyname_test.go b/integrationTests/tests/c_create_key_by_keyname_test.go new file mode 100644 index 0000000..285e47c --- /dev/null +++ b/integrationTests/tests/c_create_key_by_keyname_test.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateKeyByKeyNamePlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with label integrationTestKeyRSAName using name rsa-2048", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/type/rsa-2048/integration_test_key_rsa_name",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSAName", + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSAName"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSAName",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSAName_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test Remove Key RSA Key with name integrationTestKeyRSAName", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa_name",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_rsa_key_test.go b/integrationTests/tests/c_create_rsa_key_test.go new file mode 100644 index 0000000..90c1a10 --- /dev/null +++ b/integrationTests/tests/c_create_rsa_key_test.go @@ -0,0 +1,250 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["publicKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Public Key got %s","null").Error()) + } + if(resp.Data["privateKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Private Key got %s","null").Error()) + } + }) + t.Run("C.8 Update password RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/update-password",map[string]interface{}{ + "password":"", + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Test Remove Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_smart_rsa_key_test.go b/integrationTests/tests/c_create_smart_rsa_key_test.go new file mode 100644 index 0000000..dfdd792 --- /dev/null +++ b/integrationTests/tests/c_create_smart_rsa_key_test.go @@ -0,0 +1,255 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateSmartRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_smart_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_smart_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Block Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/block",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.8 UnBlock Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/unblock",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Update password Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/update-password",map[string]interface{}{ + "password":nil, + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/d_operations_on_key_test.go b/integrationTests/tests/d_operations_on_key_test.go new file mode 100644 index 0000000..8dc951b --- /dev/null +++ b/integrationTests/tests/d_operations_on_key_test.go @@ -0,0 +1,329 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestOperationsOnKeyPlugin(t *testing.T) { + + t.Run("D.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.2 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.3 Test Encrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.4 Test Encrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.5 Test Decrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.6 Test Decrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_key_aes",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.7 Test Sign using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + }) + t.Run("D.8 Test Verify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/verify/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "keyVersion":"v1", + "signatureAlgorithm":"SHA256_WITH_RSA", + "signature":resp.Data["signature"].(string), + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid got %s","null").Error()) + } + if(resp.Data["signatureValid"]==false){ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid %s got %s","true",resp.Data["signatureValid"]).Error()) + } + }) + t.Run("D.9 Test Modify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/modify",map[string]interface{}{ + "simplePolicy":`{"test":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnydX62tLYNF+Op1SRnX6avkkyQWlpYPagH85zxaGnMlZoMioqgjSOCuRvjaP7Y5noPMYayp3gJ2PwLXvw9+JlnL+iwklOcpONSa6gDoCDsk26DOoY0ELEPaGdW61mc2bj2hOQE0GEpPsRywJoRLS3B2e8bqRfAniAfGsUq3MK09iL5YOCuUCHCUiR9iZMSt0+Ek/kE4TrazbOCev1g6Ux2vOyTuQ6mF3wVuqwd8RhfvlNNKXbD2GD/jR3BwuhaodwzRPmDyDQPmEMwornxrMLavTcC+Igb4k5qol0Di6Oq8axpBvrH7KlxHT11Wd+ALKCsqoPSGxcIbd6TdN+ag9AQIDAQAB"}`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.11 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/go.mod b/integrationTests/tests/go.mod new file mode 100644 index 0000000..02bc999 --- /dev/null +++ b/integrationTests/tests/go.mod @@ -0,0 +1,6 @@ +module securosys.ch/integration/tests + +replace securosys.ch/integration/client => ./../client +replace securosys.ch/test-helpers => ./../../testHelpers + +go 1.19 diff --git a/integrationTests/tests/go.sum b/integrationTests/tests/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..0111058 --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.1.0 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..b55e030 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_API_URL", + "auth": "TOKEN", + "bearertoken": "TSB_BEARER_TOKEN", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/go.work b/tests/go.work new file mode 100644 index 0000000..7c33c4f --- /dev/null +++ b/tests/go.work @@ -0,0 +1,5 @@ +go 1.21 + +use ( + ./ +) \ No newline at end of file diff --git a/tests/go.work.sum b/tests/go.work.sum new file mode 100644 index 0000000..aff7933 --- /dev/null +++ b/tests/go.work.sum @@ -0,0 +1,163 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} diff --git a/tests/path_mariadb_integration_test.go b/tests/path_mariadb_integration_test.go new file mode 100644 index 0000000..b9b856e --- /dev/null +++ b/tests/path_mariadb_integration_test.go @@ -0,0 +1,111 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIntegrationMariaDB(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("A) add config", testEnv.AddConfig) + + t.Run("B) Test Creating RSA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + }) + t.Run("C)Add generate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("D)Read secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "integrations/mariadb/test/v1?key_name=custom_rsa_2048&cipher_algorithm=RSA", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("E) Rotate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("F) List secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "integrations/mariadb", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("G) Delete secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "integrations/mariadb/test", + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("H) Test Delete RSA key", func(t *testing.T) { + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + assert.NoError(t, err) + }) +} From 0e76b193b6c90309d76d463ae2af5a1e7803de42 Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Wed, 31 Jan 2024 10:14:55 +0100 Subject: [PATCH 11/16] Release v.1.1.0 --- .github/ISSUE_TEMPLATE/bug-report-sse.md | 49 + .github/ISSUE_TEMPLATE/feature-request-sse.md | 33 + .gitignore | 4 + LICENSE | 201 ++ Makefile | 201 ++ Readme.md | 1145 ++++++++++++ backend/backend.go | 140 ++ backend/go.mod | 62 + backend/go.sum | 223 +++ backend/path_config.go | 294 +++ backend/path_help.go | 452 +++++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 +++ backend/path_hsm_key_bls.go | 259 +++ backend/path_hsm_key_camellia.go | 225 +++ backend/path_hsm_key_chacha20.go | 208 +++ backend/path_hsm_key_dsa.go | 273 +++ backend/path_hsm_key_ec.go | 270 +++ backend/path_hsm_key_ed.go | 271 +++ backend/path_hsm_key_import.go | 306 ++++ backend/path_hsm_key_rsa.go | 273 +++ backend/path_hsm_key_tdea.go | 208 +++ backend/path_hsm_key_with_name.go | 295 +++ backend/path_hsm_keys.go | 1359 ++++++++++++++ backend/path_hsm_operations.go | 1631 +++++++++++++++++ backend/path_hsm_requests.go | 298 +++ backend/path_mariadb_integration.go | 666 +++++++ client/client.go | 48 + client/client_tsb.go | 1023 +++++++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + .../alpine3/docker-compose-alpine3.yml | 56 + docker-builder/build-in-docker.sh | 12 + etc/example/mariaDb.cfg | 22 + etc/example/policy.json | 93 + etc/release_notes/Release_Notes.md | 29 + go.mod | 80 + go.sum | 254 +++ go.work | 8 + go.work.sum | 164 ++ helpers/consts.go | 53 + helpers/functions.go | 234 +++ helpers/go.mod | 57 + helpers/go.sum | 223 +++ helpers/mariadb_structs.go | 82 + helpers/structs.go | 316 ++++ integrationTests/client/client.go | 30 + integrationTests/client/client_config.go | 15 + integrationTests/client/go.mod | 24 + integrationTests/client/go.sum | 58 + integrationTests/docker/docker-compose.yml | 39 + .../docker/docker-files/MariaDB_Dockerfile | 2 + .../docker/mysql-config/hashicorp.cnf | 18 + .../tests/a_enable_plugin_test.go | 48 + .../tests/b_config_plugin_test.go | 55 + .../tests/c_create_aes_key_test.go | 234 +++ .../tests/c_create_key_by_keyname_test.go | 93 + .../tests/c_create_rsa_key_test.go | 250 +++ .../tests/c_create_smart_rsa_key_test.go | 255 +++ .../tests/d_operations_on_key_test.go | 329 ++++ integrationTests/tests/go.mod | 6 + integrationTests/tests/go.sum | 0 project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 +++ testHelpers/test_client_tsb.go | 151 ++ testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 ++++++++ tests/go.mod | 66 + tests/go.sum | 223 +++ tests/go.work | 5 + tests/go.work.sum | 163 ++ tests/path_config_test.go | 153 ++ tests/path_hsm_key_aes_test.go | 133 ++ tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 ++ tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 ++ tests/path_hsm_key_tdea_test.go | 136 ++ tests/path_hsm_key_using_type_name_test.go | 245 +++ tests/path_hsm_keys_rotation_test.go | 836 +++++++++ tests/path_hsm_keys_test.go | 312 ++++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++++ tests/path_hsm_operations_sign_test.go | 647 +++++++ tests/path_hsm_operations_unwrap_test.go | 675 +++++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++++++++ tests/path_hsm_operations_wrap_test.go | 242 +++ tests/path_hsm_requests_test.go | 299 +++ tests/path_mariadb_integration_test.go | 111 ++ 95 files changed, 23286 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-sse.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-sse.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 backend/path_mariadb_integration.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 docker-builder/alpine3/docker-compose-alpine3.yml create mode 100644 docker-builder/build-in-docker.sh create mode 100644 etc/example/mariaDb.cfg create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 go.work create mode 100644 go.work.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/mariadb_structs.go create mode 100644 helpers/structs.go create mode 100644 integrationTests/client/client.go create mode 100644 integrationTests/client/client_config.go create mode 100644 integrationTests/client/go.mod create mode 100644 integrationTests/client/go.sum create mode 100644 integrationTests/docker/docker-compose.yml create mode 100644 integrationTests/docker/docker-files/MariaDB_Dockerfile create mode 100644 integrationTests/docker/mysql-config/hashicorp.cnf create mode 100644 integrationTests/tests/a_enable_plugin_test.go create mode 100644 integrationTests/tests/b_config_plugin_test.go create mode 100644 integrationTests/tests/c_create_aes_key_test.go create mode 100644 integrationTests/tests/c_create_key_by_keyname_test.go create mode 100644 integrationTests/tests/c_create_rsa_key_test.go create mode 100644 integrationTests/tests/c_create_smart_rsa_key_test.go create mode 100644 integrationTests/tests/d_operations_on_key_test.go create mode 100644 integrationTests/tests/go.mod create mode 100644 integrationTests/tests/go.sum create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/go.work create mode 100644 tests/go.work.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go create mode 100644 tests/path_mariadb_integration_test.go diff --git a/.github/ISSUE_TEMPLATE/bug-report-sse.md b/.github/ISSUE_TEMPLATE/bug-report-sse.md new file mode 100644 index 0000000..40777e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-sse.md @@ -0,0 +1,49 @@ +--- +name: Bug report SSE +about: Create a report to help us improve +title: "[BUG] " +labels: '' +assignees: Peter-FNet + +--- + + + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment:** +* Vault Server Version (retrieve with `vault status`): +* Vault CLI Version (retrieve with `vault version`): +* Server Operating System/Architecture: + +Vault server configuration file(s): + +```hcl +# Paste your Vault config here. +# Be sure to scrub any sensitive values +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request-sse.md b/.github/ISSUE_TEMPLATE/feature-request-sse.md new file mode 100644 index 0000000..8264e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-sse.md @@ -0,0 +1,33 @@ +--- +name: Feature request SSE +about: Suggest an idea for this project +title: "[FEAT]" +labels: '' +assignees: Peter-FNet + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Explain any additional use-cases** +If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5375b60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +builds +vault +deploy +.gitlab-ci.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a142d1d --- /dev/null +++ b/Makefile @@ -0,0 +1,201 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` + +ifndef ARTIFACT_NAME +override ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +endif + +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + make release-alpine3 + echo "Finished!"; + +release-alpine3: + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-amd64 + make clean-docker-builder IMAGE=amd64/golang + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-i386 + make clean-docker-builder IMAGE=i386/golang + +clean-docker-builder: + @if [ "$$(docker images | grep '$(IMAGE)')" != "" ]; then \ + docker rmi -f $$(docker images | grep '$(IMAGE)' | awk '{ print $$3}') 2> /dev/null || true ; \ + fi; + docker volume prune -f + docker container prune -f + docker network prune -f + +run-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml up --build -d +clean-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml down --remove-orphans --rmi all + docker volume prune -f + docker container prune -f +integration-tests: + rm -fr integrationTests/docker/plugins/securosys-hsm + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -o integrationTests/docker/plugins/securosys-hsm cmd/securosys-hsm/main.go + make run-docker-test-container + + sleep 5 + go install github.com/jstemmer/go-junit-report/v2@latest + cd integrationTests/tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}integration_junit_report.xml -set-exit-code + + + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 15m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4828e0e --- /dev/null +++ b/Readme.md @@ -0,0 +1,1145 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Integrations](#integrations) + - [MariaDB](#mariadb) + - [Example usage](#mariadb-usage-example) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate and `keypath` with local PATH to the key. +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for Certificate authorization**: +```shell +$ vault write securosys-hsm/config +auth="CERT" +certpath="local_absolute_path_to_certificate.pem" +keypath="local_absolute_path_to_private.key" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=CERT' \ +--data-urlencode 'certpath=local_absolute_path_to_certificate.pem' \ +--data-urlencode 'keypath=local_absolute_path_to_private.pem' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Integrations +### MariaDB +Encryption on MariaDB can be enabled using existing plugin [Hashicorp Key Management Plugin](https://mariadb.com/kb/en/hashicorp-key-management-plugin/) +This integration stores generated secret in Secrets engine, encrypted by provided key. +**Supported Key Types**/**Algorithm** combinations: +| Key Type | Algorithm | +|----------|:-------------:| +| **RSA** |RSA_PADDING_OAEP_WITH_SHA512
RSA
RSA_PADDING_OAEP_WITH_SHA224
RSA_PADDING_OAEP_WITH_SHA256
RSA_PADDING_OAEP_WITH_SHA1
RSA_PADDING_OAEP
RSA_PADDING_OAEP_WITH_SHA384
RSA_NO_PADDING| +|**AES**|AES_GCM
AES_CTR
AES_ECB
AES_CBC_NO_PADDING
AES | +| **CHACHA20** | CHACHA20
CHACHA20_AEAD| +| **CAMELLIA** | CAMELLIA
CAMELLIA_CBC_NO_PADDING
CAMELLIA_ECB | +|**TDEA**| TDEA_CBC
TDEA_ECB
TDEA_CBC_NO_PADDING | + +>**Note** - Plugin supports **asynchronous decrypt operation** using key type **RSA** with **policy** with setup **ruleUse**. Using the key with policy will **stop** the decrypt operation and **wait for approvals** to be collected. + +There are a **serval steps** that is needed to be done before setup encryption on MariaDB +1) [Create / Register key](#manage-keys) into **Secrets Engine** +1) Generate new **secret** and encrypt it using stored key + ```shell + $ vault write securosys-hsm/integrations/mariadb/{secret-name} + keyName={key-name-from-secret-engine} + cipherAlgorithm={cipher-algorithm} + [additionalAuthenticationData={additional-authentication-data}] + [tagLength={tag-length}] + [password={password-for-a-key}] + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/integrations/mariadb/{secret-name} ' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName={key-name-from-secret-engine}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + >**Note** - Every request on this endpoint using same **key name** and **secret name** will **rotate secret** +1) The last step is add this configuration to **my.cfg** + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" + loose-hashicorp-key-management-token="{vault_access_token}" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + >**Note** - In **loose-hashicorp-key-management-vault-url** url need to ends with **&version=**. Plugin from **MariaDB** automatically add to end of url **number of secret version** +#### MariaDB usage example +This example using default configuration for **Hashicorp Vault dev server**. +| Data | Value | +|----------|:-------------:| +| **vault address** | https://localhost:8200 | +| **vault access token** | root | +1) **Create key** *MariaDBEncryptionKey* with key size *4096* with attributes at last "decrypt" equals *true* on HSM and store it as *mariadb_encryption_key* on **Secrets engine** + ```shell + $ vault write securosys-hsm/keys/rsa/mariadb_encryption_key + keyLabel="MariaDBEncryptionKey" + keySize=4096 + attributes='{"decrypt": true,"sign": false,"unwrap": false,"derive": true,"sensitive": true,"extractable": false,"modifiable": false,"copyable": false,"destroyable": true}' + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/keys/rsa/mariadb_encryption_key' \ + --header 'X-Vault-Token: root' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel=MariaDBEncryptionKey' \ + --data-urlencode 'keySize=4096' \ + --data-urlencode 'attributes={ + "decrypt": true, + "sign": false, + "unwrap": false, + "derive": true, + "sensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": false, + "copyable": false, + "destroyable": true + }' + ``` +1) Generate new **secret** called *mariadb_secret* and **encrypt it** using cipher algorithm *RSA* and stored key *mariadb_encryption_key* in **Secrets engine** + ```shell + $ vault write securosys-hsm/integrations/mariadb/mariadb_secret + keyName=mariadb_encryption_key + cipherAlgorithm=RSA + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret ' \ + --header 'X-Vault-Token: root' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName=mariadb_encryption_key' \ + --data-urlencode 'cipherAlgorithm=RSA' + ``` +3. Configure **MariaDB plugin** "Hashicorp Key Management" in database configuration in **my.cnf** + + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret/?key_name=mariadb_encryption_key&cipher_algorithm=RSA&version=" + loose-hashicorp-key-management-token="root" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + + + +--- +## Appendix +### Frequently Asked Questions +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..67cf38a --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,140 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + pathMariaDBIntegration(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..29a1fac --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,294 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "keypath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to key", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "KeyPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if keypath, ok := data.GetOk("keypath"); ok { + config.KeyPath = keypath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing keypath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.KeyPath) + + if err != nil { + return nil, fmt.Errorf("Keypath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..8281fe0 --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,452 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..32954d9 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string), map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy, map[string]string{}) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil, map[string]string{}) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString, nil) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..e24fe58 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} diff --git a/backend/path_mariadb_integration.go b/backend/path_mariadb_integration.go new file mode 100644 index 0000000..0101c1d --- /dev/null +++ b/backend/path_mariadb_integration.go @@ -0,0 +1,666 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for create Camellia Keys +func pathMariaDBIntegration(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "keyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsDelete, + }, + }, + HelpSynopsis: pathIntegrationMariaDBWriteHelpSynopsis, + HelpDescription: pathIntegrationMariaDBWriteHelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("version") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV1HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV1HelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV2HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV2HelpDescription, + }, + { + Pattern: "integrations/mariadb/?$", + Fields: map[string]*framework.FieldSchema{}, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsList, + }, + }, + HelpSynopsis: pathIntegrationMariaDBListHelpSynopsis, + HelpDescription: pathIntegrationMariaDBListHelpDescription, + }, + } +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "intergration/mariadb/") + if err != nil { + return nil, err + } + secrets := make([]string, 0, len(entries)) + secretsInfo := make(map[string]interface{}) + for _, name := range entries { + secrets = append(secrets, name) + secret, err := b.GetMariaDBSecret(ctx, req.Storage, name) + if err == nil { + secretsInfo[name] = map[string]interface{}{ + "KeyName": secret.KeyName, + "Version": secret.CurrentVersion, + "Created": secret.Created.Name, + "Updated": secret.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(secrets, secretsInfo), nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, errGet := b.GetMariaDBSecret(ctx, req.Storage, name) + if errGet != nil { + return nil, fmt.Errorf("error deleting mariadb secret: %w", errGet) + } + if storedSecret == nil { + return nil, fmt.Errorf("error deleting mariadb secret: secret with name %s not exists", d.Get("name").(string)) + + } + + err := req.Storage.Delete(ctx, "intergration/mariadb/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + rotate := false + if storedSecret != nil { + rotate = true + // return nil, fmt.Errorf("error secret with name: %s exists", name) + } else { + storedSecret = &helpers.MariaDBSecretEntry{} + + } + + keyName := d.Get("keyName").(string) + + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload := b64.StdEncoding.EncodeToString([]byte(helpers.GeneratePassword(32, false, false, false, true))) + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + sysView := b.System() + creator := helpers.Entity{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + creator.Aliases = entity.Aliases + creator.Id = entity.ID + creator.Name = entity.Name + creator.Date = time.Now().UTC() + + } else { + creator.Aliases = nil + creator.Id = "root" + creator.Name = "root" + creator.Date = time.Now().UTC() + + } + var messageAuthenticationCode *string = nil + if result["messageAuthenticationCode"] != nil { + temp := result["messageAuthenticationCode"].(string) + messageAuthenticationCode = &temp + } + var initializationVector *string = nil + if result["initializationVector"] != nil { + temp := result["initializationVector"].(string) + initializationVector = &temp + } + if !rotate { + storedSecret.InitSecret(keyName, keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + } else { + storedSecret.RotateSecret(keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + + } + if err := SetMariaDBSecret(ctx, req.Storage, name, storedSecret); err != nil { + return nil, err + } + + response := map[string]interface{}{} + now := storedSecret.GetActiveVersion().Created.Date + version := storedSecret.GetActiveVersion().Version + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + query := d.Get("query").(string) + if strings.HasPrefix(query, "?") { + query = query[1:] + } + params, err := url.ParseQuery(query) + + if query == "" { + str := "" + for key, value := range req.Data { + str = str + key + "=" + value.(string) + "&" + } + str = str[:len(str)-1] + params, err = url.ParseQuery(str) + } + + if err != nil { + return nil, err + } + name := d.Get("name").(string) + + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + if storedSecret == nil { + return nil, fmt.Errorf("error secret with name: %s not exists", name) + } + + version := "1" + if params.Has("version") { + if !strings.Contains(params.Get("version"), "?version=") { + version = storedSecret.CurrentVersion + } else { + parts := strings.Split(params.Get("version"), "?version=") + version = "v" + parts[1] + } + } else { + ver, ok := d.GetOk("version") + if !ok { + return nil, fmt.Errorf("error: missing version") + } + version = ver.(string) + } + + if !params.Has("key_name") { + return nil, fmt.Errorf("key_name query param not exists") + } + keyEntry, err := b.GetKey(ctx, req.Storage, params.Get("key_name")) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + keyName := params.Get("key_name") + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + + if !helpers.ContainsKey(storedSecret.Versions, version) { + return nil, fmt.Errorf("Secret version %s is not exists.", version) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload := storedSecret.GetVersion(version).EncryptedSecret + + if !params.Has("cipher_algorithm") { + return nil, fmt.Errorf("cipher_algorithm query param not exists") + } + + cipherAlgorithm := params.Get("cipher_algorithm") + if keyEntry.KeyTypeName != "aes256-gcm96" && cipherAlgorithm == "" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVectorString := "" + if params.Has("initialization_vector") { + initializationVectorString = params.Get("initialization_vector") + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + passwordString := "" + if params.Has("password") { + passwordString = params.Get("password") + } + tagLengthInt := -1 + if params.Has("tag_length") { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + } + if keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationDataString := "" + if params.Has("aad") { + additionalAuthenticationDataString = params.Get("aad") + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationDataString) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData (param aad) is not valid base64 string") + } + } + client, err := b.GetClient(ctx, req.Storage) + async := false + decrypted := "" + if len(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + async = true + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString, map[string]string{"integration": "MariaDB Encrypt"}) + if errEnc != nil { + return nil, errEnc + } + var resp *helpers.RequestResponse + resp, _, _ = client.GetRequest(requestId) + for resp.Status == "PENDING" { + time.Sleep(1000) + resp, _, _ = client.GetRequest(requestId) + } + if resp.Status != "EXECUTED" { + return nil, fmt.Errorf("error on async decrypt. Expected Status '%s' got '%s'", "EXECUTED", resp.Status) + } + decrypted = resp.Result + + } + } + } + if !async { + resultSync, errEnc := client.Decrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + decrypted = resultSync["payload"].(string) + } + + if cipherAlgorithm == "AES_ECB" || + cipherAlgorithm == "AES_CBC_NO_PADDING" || + cipherAlgorithm == "CAMELLIA_ECB" || + cipherAlgorithm == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + decoded, _ := base64.StdEncoding.DecodeString(decrypted) + response := map[string]interface{}{} + response["data"] = map[string]interface{}{"data": string(decoded)} + now := storedSecret.GetVersion(version).Created.Date + + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} + +// This function helps with saving key in Secrets Engine +func SetMariaDBSecret(ctx context.Context, s logical.Storage, name string, secretEntry *helpers.MariaDBSecretEntry) error { + entry, err := logical.StorageEntryJSON("intergration/mariadb/"+name, secretEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage secret") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetMariaDBSecret(ctx context.Context, s logical.Storage, name string) (*helpers.MariaDBSecretEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "intergration/mariadb/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var secret helpers.MariaDBSecretEntry + + if err := entry.DecodeJSON(&secret); err != nil { + return nil, err + } + return &secret, nil +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..b50c7e2 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1023 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + KeyPath: data["keypath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + ` + passwordString + ` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy, customMetaData map[string]string) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo, customMetaData) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString := "" + if len(keyToBeWrappedPasswordJson) > 2 { + keyToBeWrappedPasswordString = `"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString := "" + if len(wrapKeyPasswordJson) > 2 { + wrapKeyPasswordString = `"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + ` + keyToBeWrappedPasswordString + ` + "wrapKeyName": "` + wrapKeyName + `", + ` + wrapKeyPasswordString + ` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + ` + passwordString + ` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + ` + passwordString + ` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + ` + passwordString + ` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + ` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString := "" + if len(charsNewPasswordJson) > 2 { + newPasswordString = `"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + newPasswordString + ` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + passwordString + ` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + clientTLSCert, err := tls.LoadX509KeyPair(c.Auth.CertPath, c.Auth.KeyPath) + if err != nil { + log.Fatalf("Error loading certificate and key file: %v", err) + return nil, err, 0 + } + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + InsecureSkipVerify: true, + Certificates: []tls.Certificate{clientTLSCert}, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/docker-builder/alpine3/docker-compose-alpine3.yml b/docker-builder/alpine3/docker-compose-alpine3.yml new file mode 100644 index 0000000..1190d88 --- /dev/null +++ b/docker-builder/alpine3/docker-compose-alpine3.yml @@ -0,0 +1,56 @@ + version: "3.3" + services: + golang-builder-alpine3-amd64: + platform: linux/amd64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=amd64 + image: amd64/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-amd64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-i386: + platform: linux/i386 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=386 + image: i386/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-i386 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-arm64: + platform: linux/arm64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=arm64 + image: arm64v8/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-arm64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" \ No newline at end of file diff --git a/docker-builder/build-in-docker.sh b/docker-builder/build-in-docker.sh new file mode 100644 index 0000000..adc15b2 --- /dev/null +++ b/docker-builder/build-in-docker.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd .. +echo "Build ${ARTIFACT_NAME} in ${DOCKER_OS}_${DOCKER_ARCH}"; + cd /src + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; + cd builds; + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; + zip -9 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; + shasum -a 256 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; + cd ..; + rm builds/securosys-hsm; + rm builds/securosys-hsm_SHA256SUM; \ No newline at end of file diff --git a/etc/example/mariaDb.cfg b/etc/example/mariaDb.cfg new file mode 100644 index 0000000..298e73a --- /dev/null +++ b/etc/example/mariaDb.cfg @@ -0,0 +1,22 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" +loose-hashicorp-key-management-token="{vault_access_token}" +loose-hashicorp-key-management-check-kv-version="off" +#max timeout is 86400 seconds +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +#1 year in miliseconds +loose-hashicorp-key-management-cache-timeout=31556952000 +#1 year in miliseconds +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +#Example of innodb config +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = ON +innodb_encrypt_log = ON +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 \ No newline at end of file diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..8e00e02 --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,93 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..6eebb05 --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,29 @@ +# Securosys Hashicorp Vault Secrets Engine 1.1.0 +Issued: Dec, 6, 2023 +## Documentation Change +- Update Readme.md - added information about supporting and how to configure encryption on MariaDB +## Feature +- Added integration with MariaDB encryption +## Bugfix +- Fixed authentication with TSB using mTLS + +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build/ + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2d78c0c --- /dev/null +++ b/go.mod @@ -0,0 +1,80 @@ +module secretengine + +go 1.21 + +toolchain go1.21.2 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers + +replace securosys.ch/tests => ./tests + +replace securosys.ch/integration/client => ./integrationTests/client + +replace securosys.ch/integration/tests => ./integrationTests/tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/frankban/quicktest v1.14.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afae25d --- /dev/null +++ b/go.sum @@ -0,0 +1,254 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work new file mode 100644 index 0000000..ad36518 --- /dev/null +++ b/go.work @@ -0,0 +1,8 @@ +go 1.21 + +use ( + ./ + ./backend + ./integrationTests/client + ./integrationTests/tests +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..976ca94 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,164 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..bdc47e4 --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "math/rand" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} +func GetVersionNumber(version string) int { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + return versionInt +} +func GetVersionString(version string) string { + return strings.Replace(version, "v", "", 1) +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string, customMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + for key, value := range customMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + specialBytes = "!@#$%^&*()_+-=[]{}\\|;':\",.<>/?`~" + numBytes = "0123456789" + hexDecimalBytes = "0123456789ABCDEF" +) + +func GeneratePassword(length int, useLetters bool, useSpecial bool, useNum bool, useHexadecimal bool) string { + rand.Seed(time.Now().UnixNano()) + b := make([]byte, length) + arrayForRandom := make([]byte, 0) + if useLetters { + arrayForRandom = append(arrayForRandom, letterBytes...) + } + if useSpecial { + arrayForRandom = append(arrayForRandom, specialBytes...) + } + if useNum { + arrayForRandom = append(arrayForRandom, numBytes...) + } + if useHexadecimal { + arrayForRandom = append(arrayForRandom, hexDecimalBytes...) + + } + + for i := range b { + b[i] = arrayForRandom[rand.Intn(len(arrayForRandom))] + } + return string(b) +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/mariadb_structs.go b/helpers/mariadb_structs.go new file mode 100644 index 0000000..97210ac --- /dev/null +++ b/helpers/mariadb_structs.go @@ -0,0 +1,82 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// INTEGRATION MARIADB STRUCTS + +type MariaDBSecretEntry struct { + KeyName string `json:"keyName"` + Versions map[string]MariaDBSecretVersion `json:"secretVersions"` + CurrentVersion string `json:"defaultVersion"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +// Struct of keys stored inside the Vault +type MariaDBSecretVersion struct { + KeyVersion string `json:"keyVersion"` + EncryptedSecret string `json:"encryptedSecret"` + MessageAuthenticationCode *string `json:"messageAuthenticationCode"` + InitializationVector *string `json:"initializationVector"` + Version string `json:"version"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (s *MariaDBSecretEntry) InitSecret(keyName string, keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, creator Entity) { + s.CurrentVersion = "v1" + s.KeyName = keyName + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = "v1" + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = creator + secretVersion.Updated = creator + s.Created = creator + s.Updated = creator + s.Versions = make(map[string]MariaDBSecretVersion) + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) RotateSecret(keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, updater Entity) { + newSecretVersion := GetNewVersion(s.CurrentVersion) + s.CurrentVersion = newSecretVersion + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = newSecretVersion + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = updater + secretVersion.Updated = updater + s.Updated = updater + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) GetActiveVersion() MariaDBSecretVersion { + return s.Versions[s.CurrentVersion] +} +func (s *MariaDBSecretEntry) GetVersion(keyVersion string) MariaDBSecretVersion { + return s.Versions[keyVersion] +} + +// END INTEGRATION MARIADB STRUCTS diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9782f2d --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,316 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/integrationTests/client/client.go b/integrationTests/client/client.go new file mode 100644 index 0000000..70d4bee --- /dev/null +++ b/integrationTests/client/client.go @@ -0,0 +1,30 @@ +package integrationClient + +import ( + "fmt" + "log" + "os" + "time" + + "github.com/hashicorp/vault-client-go" +) + +func InitVaultClient() (*vault.Client){ + + // prepare a client with the given base address + client, err := vault.New( + vault.WithAddress(VaultConfig.Url+":"+fmt.Sprint(VaultConfig.Port)), + vault.WithRequestTimeout(30*time.Second), + ) + if err != nil { + log.Fatal(err) + os.Exit(1); + } + + // authenticate with a root token (insecure) + if err := client.SetToken(VaultConfig.RootToken); err != nil { + log.Fatal(err) + os.Exit(1); + } + return client; +} \ No newline at end of file diff --git a/integrationTests/client/client_config.go b/integrationTests/client/client_config.go new file mode 100644 index 0000000..148f2a9 --- /dev/null +++ b/integrationTests/client/client_config.go @@ -0,0 +1,15 @@ +package integrationClient + +type VaultClientConfig struct { + Port int + Url string + RootToken string + SecretsEnginePath string +} + +var VaultConfig VaultClientConfig=VaultClientConfig{ + Port: 8251, + Url: "http://127.0.0.1", + RootToken: "root", + SecretsEnginePath: "securosys-hsm", +} \ No newline at end of file diff --git a/integrationTests/client/go.mod b/integrationTests/client/go.mod new file mode 100644 index 0000000..02d12cd --- /dev/null +++ b/integrationTests/client/go.mod @@ -0,0 +1,24 @@ +module securosys.ch/integration/client + +go 1.21 + +toolchain go1.21.2 + +require github.com/hashicorp/vault-client-go v0.4.2 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stretchr/testify v1.8.2 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect +) diff --git a/integrationTests/client/go.sum b/integrationTests/client/go.sum new file mode 100644 index 0000000..3a52bd0 --- /dev/null +++ b/integrationTests/client/go.sum @@ -0,0 +1,58 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/vault-client-go v0.4.2 h1:XeUXb5jnDuCUhC8HRpkdGPLh1XtzXmiOnF0mXEbARxI= +github.com/hashicorp/vault-client-go v0.4.2/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integrationTests/docker/docker-compose.yml b/integrationTests/docker/docker-compose.yml new file mode 100644 index 0000000..1b00ff4 --- /dev/null +++ b/integrationTests/docker/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.0" +name: hashicorp-vault-test-containers +services: + hashicorp-vault-test: + image: hashicorp/vault:latest + container_name: "hashicorp-vault-test" + environment: + VAULT_DEV_ROOT_TOKEN_ID: root + VAULT_ADDR: 'https://0.0.0.0:8251' + VAULT_LOCAL_CONFIG: '{"listener": [{"tcp":{"address": "0.0.0.0:8251","tls_disable":"1"}}], "default_lease_ttl": "168h", "max_lease_ttl": "720h"}, "ui": true}' + volumes: + - ./plugins/:/vault/plugins + cap_add: + - IPC_LOCK + healthcheck: + retries: 5 + ports: + - "8251:8251" + privileged: true + command: server -dev -dev-root-token-id=root -dev-plugin-dir=/vault/plugins + networks: + - web + mariadb-test-integration: + build: + dockerfile: ./docker-files/MariaDB_Dockerfile + container_name: "mariadb-test-integration" + restart: always + environment: + MARIADB_ROOT_PASSWORD: example + volumes: + - ./mysql-config:/etc/mysql/conf.d + - ./db:/var/lib/mysql + networks: + - web + +networks: + web: + external: true + \ No newline at end of file diff --git a/integrationTests/docker/docker-files/MariaDB_Dockerfile b/integrationTests/docker/docker-files/MariaDB_Dockerfile new file mode 100644 index 0000000..7e5d37a --- /dev/null +++ b/integrationTests/docker/docker-files/MariaDB_Dockerfile @@ -0,0 +1,2 @@ +FROM mariadb:latest +RUN apt-get update && apt-get install -y mariadb-plugin-hashicorp-key-management diff --git a/integrationTests/docker/mysql-config/hashicorp.cnf b/integrationTests/docker/mysql-config/hashicorp.cnf new file mode 100644 index 0000000..d628bc7 --- /dev/null +++ b/integrationTests/docker/mysql-config/hashicorp.cnf @@ -0,0 +1,18 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="http://192.168.96.3:8251/v1/securosys-hsm/integrations/mariadb/test_async/?cipher_algorithm=RSA&key_name=rsa_with_policy&version=" +loose-hashicorp-key-management-token="root" +loose-hashicorp-key-management-check-kv-version="off" +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +loose-hashicorp-key-management-cache-timeout=31556952000 +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = OFF +innodb_encrypt_log = OFF +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 diff --git a/integrationTests/tests/a_enable_plugin_test.go b/integrationTests/tests/a_enable_plugin_test.go new file mode 100644 index 0000000..d16575a --- /dev/null +++ b/integrationTests/tests/a_enable_plugin_test.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "testing" + + "github.com/hashicorp/vault-client-go/schema" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestEnablePlugin(t *testing.T) { + + t.Run("A.1 Test Enable Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.System.MountsEnableSecretsEngine(ctx,integrationClient.VaultConfig.SecretsEnginePath,schema.MountsEnableSecretsEngineRequest{ + Type: "securosys-hsm", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/b_config_plugin_test.go b/integrationTests/tests/b_config_plugin_test.go new file mode 100644 index 0000000..d777766 --- /dev/null +++ b/integrationTests/tests/b_config_plugin_test.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfigPlugin(t *testing.T) { + + t.Run("B.1 Test Config Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/config",testHelpers.ConfigParams) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data["result"]==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s","null").Error()) + } + + if(!strings.Contains(resp.Data["result"].(string),"Connection successful:")){ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s",resp.Data["result"]).Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_aes_key_test.go b/integrationTests/tests/c_create_aes_key_test.go new file mode 100644 index 0000000..ccffd1b --- /dev/null +++ b/integrationTests/tests/c_create_aes_key_test.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateAESKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_aes"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_aes got %s","null").Error()) + } + }) + t.Run("C.3 Read AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["secretKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Key Secret got %s","null").Error()) + } + }) + t.Run("C.8 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_key_by_keyname_test.go b/integrationTests/tests/c_create_key_by_keyname_test.go new file mode 100644 index 0000000..285e47c --- /dev/null +++ b/integrationTests/tests/c_create_key_by_keyname_test.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateKeyByKeyNamePlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with label integrationTestKeyRSAName using name rsa-2048", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/type/rsa-2048/integration_test_key_rsa_name",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSAName", + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSAName"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSAName",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSAName_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test Remove Key RSA Key with name integrationTestKeyRSAName", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa_name",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_rsa_key_test.go b/integrationTests/tests/c_create_rsa_key_test.go new file mode 100644 index 0000000..90c1a10 --- /dev/null +++ b/integrationTests/tests/c_create_rsa_key_test.go @@ -0,0 +1,250 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["publicKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Public Key got %s","null").Error()) + } + if(resp.Data["privateKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Private Key got %s","null").Error()) + } + }) + t.Run("C.8 Update password RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/update-password",map[string]interface{}{ + "password":"", + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Test Remove Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_smart_rsa_key_test.go b/integrationTests/tests/c_create_smart_rsa_key_test.go new file mode 100644 index 0000000..dfdd792 --- /dev/null +++ b/integrationTests/tests/c_create_smart_rsa_key_test.go @@ -0,0 +1,255 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateSmartRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_smart_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_smart_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Block Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/block",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.8 UnBlock Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/unblock",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Update password Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/update-password",map[string]interface{}{ + "password":nil, + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/d_operations_on_key_test.go b/integrationTests/tests/d_operations_on_key_test.go new file mode 100644 index 0000000..8dc951b --- /dev/null +++ b/integrationTests/tests/d_operations_on_key_test.go @@ -0,0 +1,329 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestOperationsOnKeyPlugin(t *testing.T) { + + t.Run("D.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.2 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.3 Test Encrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.4 Test Encrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.5 Test Decrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.6 Test Decrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_key_aes",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.7 Test Sign using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + }) + t.Run("D.8 Test Verify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/verify/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "keyVersion":"v1", + "signatureAlgorithm":"SHA256_WITH_RSA", + "signature":resp.Data["signature"].(string), + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid got %s","null").Error()) + } + if(resp.Data["signatureValid"]==false){ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid %s got %s","true",resp.Data["signatureValid"]).Error()) + } + }) + t.Run("D.9 Test Modify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/modify",map[string]interface{}{ + "simplePolicy":`{"test":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnydX62tLYNF+Op1SRnX6avkkyQWlpYPagH85zxaGnMlZoMioqgjSOCuRvjaP7Y5noPMYayp3gJ2PwLXvw9+JlnL+iwklOcpONSa6gDoCDsk26DOoY0ELEPaGdW61mc2bj2hOQE0GEpPsRywJoRLS3B2e8bqRfAniAfGsUq3MK09iL5YOCuUCHCUiR9iZMSt0+Ek/kE4TrazbOCev1g6Ux2vOyTuQ6mF3wVuqwd8RhfvlNNKXbD2GD/jR3BwuhaodwzRPmDyDQPmEMwornxrMLavTcC+Igb4k5qol0Di6Oq8axpBvrH7KlxHT11Wd+ALKCsqoPSGxcIbd6TdN+ag9AQIDAQAB"}`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.11 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/go.mod b/integrationTests/tests/go.mod new file mode 100644 index 0000000..02bc999 --- /dev/null +++ b/integrationTests/tests/go.mod @@ -0,0 +1,6 @@ +module securosys.ch/integration/tests + +replace securosys.ch/integration/client => ./../client +replace securosys.ch/test-helpers => ./../../testHelpers + +go 1.19 diff --git a/integrationTests/tests/go.sum b/integrationTests/tests/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..0111058 --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.1.0 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..b55e030 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_API_URL", + "auth": "TOKEN", + "bearertoken": "TSB_BEARER_TOKEN", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/go.work b/tests/go.work new file mode 100644 index 0000000..7c33c4f --- /dev/null +++ b/tests/go.work @@ -0,0 +1,5 @@ +go 1.21 + +use ( + ./ +) \ No newline at end of file diff --git a/tests/go.work.sum b/tests/go.work.sum new file mode 100644 index 0000000..aff7933 --- /dev/null +++ b/tests/go.work.sum @@ -0,0 +1,163 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} diff --git a/tests/path_mariadb_integration_test.go b/tests/path_mariadb_integration_test.go new file mode 100644 index 0000000..b9b856e --- /dev/null +++ b/tests/path_mariadb_integration_test.go @@ -0,0 +1,111 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIntegrationMariaDB(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("A) add config", testEnv.AddConfig) + + t.Run("B) Test Creating RSA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + }) + t.Run("C)Add generate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("D)Read secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "integrations/mariadb/test/v1?key_name=custom_rsa_2048&cipher_algorithm=RSA", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("E) Rotate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("F) List secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "integrations/mariadb", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("G) Delete secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "integrations/mariadb/test", + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("H) Test Delete RSA key", func(t *testing.T) { + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + assert.NoError(t, err) + }) +} From 73b930e3cbf66d77762568d1ae5ac21326241ea4 Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Wed, 31 Jan 2024 10:15:40 +0100 Subject: [PATCH 12/16] Release v.1.1.0 --- .github/ISSUE_TEMPLATE/bug-report-sse.md | 49 + .github/ISSUE_TEMPLATE/feature-request-sse.md | 33 + .gitignore | 4 + LICENSE | 201 ++ Makefile | 201 ++ Readme.md | 1145 ++++++++++++ backend/backend.go | 140 ++ backend/go.mod | 62 + backend/go.sum | 223 +++ backend/path_config.go | 294 +++ backend/path_help.go | 452 +++++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 +++ backend/path_hsm_key_bls.go | 259 +++ backend/path_hsm_key_camellia.go | 225 +++ backend/path_hsm_key_chacha20.go | 208 +++ backend/path_hsm_key_dsa.go | 273 +++ backend/path_hsm_key_ec.go | 270 +++ backend/path_hsm_key_ed.go | 271 +++ backend/path_hsm_key_import.go | 306 ++++ backend/path_hsm_key_rsa.go | 273 +++ backend/path_hsm_key_tdea.go | 208 +++ backend/path_hsm_key_with_name.go | 295 +++ backend/path_hsm_keys.go | 1359 ++++++++++++++ backend/path_hsm_operations.go | 1631 +++++++++++++++++ backend/path_hsm_requests.go | 298 +++ backend/path_mariadb_integration.go | 666 +++++++ client/client.go | 48 + client/client_tsb.go | 1023 +++++++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + .../alpine3/docker-compose-alpine3.yml | 56 + docker-builder/build-in-docker.sh | 12 + etc/example/mariaDb.cfg | 22 + etc/example/policy.json | 93 + etc/release_notes/Release_Notes.md | 29 + go.mod | 80 + go.sum | 254 +++ go.work | 8 + go.work.sum | 164 ++ helpers/consts.go | 53 + helpers/functions.go | 234 +++ helpers/go.mod | 57 + helpers/go.sum | 223 +++ helpers/mariadb_structs.go | 82 + helpers/structs.go | 316 ++++ integrationTests/client/client.go | 30 + integrationTests/client/client_config.go | 15 + integrationTests/client/go.mod | 24 + integrationTests/client/go.sum | 58 + integrationTests/docker/docker-compose.yml | 39 + .../docker/docker-files/MariaDB_Dockerfile | 2 + .../docker/mysql-config/hashicorp.cnf | 18 + .../tests/a_enable_plugin_test.go | 48 + .../tests/b_config_plugin_test.go | 55 + .../tests/c_create_aes_key_test.go | 234 +++ .../tests/c_create_key_by_keyname_test.go | 93 + .../tests/c_create_rsa_key_test.go | 250 +++ .../tests/c_create_smart_rsa_key_test.go | 255 +++ .../tests/d_operations_on_key_test.go | 329 ++++ integrationTests/tests/go.mod | 6 + integrationTests/tests/go.sum | 0 project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 +++ testHelpers/test_client_tsb.go | 151 ++ testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 ++++++++ tests/go.mod | 66 + tests/go.sum | 223 +++ tests/go.work | 5 + tests/go.work.sum | 163 ++ tests/path_config_test.go | 153 ++ tests/path_hsm_key_aes_test.go | 133 ++ tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 ++ tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 ++ tests/path_hsm_key_tdea_test.go | 136 ++ tests/path_hsm_key_using_type_name_test.go | 245 +++ tests/path_hsm_keys_rotation_test.go | 836 +++++++++ tests/path_hsm_keys_test.go | 312 ++++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++++ tests/path_hsm_operations_sign_test.go | 647 +++++++ tests/path_hsm_operations_unwrap_test.go | 675 +++++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++++++++ tests/path_hsm_operations_wrap_test.go | 242 +++ tests/path_hsm_requests_test.go | 299 +++ tests/path_mariadb_integration_test.go | 111 ++ 95 files changed, 23286 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-sse.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-sse.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 backend/path_mariadb_integration.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 docker-builder/alpine3/docker-compose-alpine3.yml create mode 100644 docker-builder/build-in-docker.sh create mode 100644 etc/example/mariaDb.cfg create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 go.work create mode 100644 go.work.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/mariadb_structs.go create mode 100644 helpers/structs.go create mode 100644 integrationTests/client/client.go create mode 100644 integrationTests/client/client_config.go create mode 100644 integrationTests/client/go.mod create mode 100644 integrationTests/client/go.sum create mode 100644 integrationTests/docker/docker-compose.yml create mode 100644 integrationTests/docker/docker-files/MariaDB_Dockerfile create mode 100644 integrationTests/docker/mysql-config/hashicorp.cnf create mode 100644 integrationTests/tests/a_enable_plugin_test.go create mode 100644 integrationTests/tests/b_config_plugin_test.go create mode 100644 integrationTests/tests/c_create_aes_key_test.go create mode 100644 integrationTests/tests/c_create_key_by_keyname_test.go create mode 100644 integrationTests/tests/c_create_rsa_key_test.go create mode 100644 integrationTests/tests/c_create_smart_rsa_key_test.go create mode 100644 integrationTests/tests/d_operations_on_key_test.go create mode 100644 integrationTests/tests/go.mod create mode 100644 integrationTests/tests/go.sum create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/go.work create mode 100644 tests/go.work.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go create mode 100644 tests/path_mariadb_integration_test.go diff --git a/.github/ISSUE_TEMPLATE/bug-report-sse.md b/.github/ISSUE_TEMPLATE/bug-report-sse.md new file mode 100644 index 0000000..40777e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-sse.md @@ -0,0 +1,49 @@ +--- +name: Bug report SSE +about: Create a report to help us improve +title: "[BUG] " +labels: '' +assignees: Peter-FNet + +--- + + + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment:** +* Vault Server Version (retrieve with `vault status`): +* Vault CLI Version (retrieve with `vault version`): +* Server Operating System/Architecture: + +Vault server configuration file(s): + +```hcl +# Paste your Vault config here. +# Be sure to scrub any sensitive values +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request-sse.md b/.github/ISSUE_TEMPLATE/feature-request-sse.md new file mode 100644 index 0000000..8264e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-sse.md @@ -0,0 +1,33 @@ +--- +name: Feature request SSE +about: Suggest an idea for this project +title: "[FEAT]" +labels: '' +assignees: Peter-FNet + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Explain any additional use-cases** +If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5375b60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +builds +vault +deploy +.gitlab-ci.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a142d1d --- /dev/null +++ b/Makefile @@ -0,0 +1,201 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` + +ifndef ARTIFACT_NAME +override ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +endif + +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + make release-alpine3 + echo "Finished!"; + +release-alpine3: + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-amd64 + make clean-docker-builder IMAGE=amd64/golang + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-i386 + make clean-docker-builder IMAGE=i386/golang + +clean-docker-builder: + @if [ "$$(docker images | grep '$(IMAGE)')" != "" ]; then \ + docker rmi -f $$(docker images | grep '$(IMAGE)' | awk '{ print $$3}') 2> /dev/null || true ; \ + fi; + docker volume prune -f + docker container prune -f + docker network prune -f + +run-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml up --build -d +clean-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml down --remove-orphans --rmi all + docker volume prune -f + docker container prune -f +integration-tests: + rm -fr integrationTests/docker/plugins/securosys-hsm + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -o integrationTests/docker/plugins/securosys-hsm cmd/securosys-hsm/main.go + make run-docker-test-container + + sleep 5 + go install github.com/jstemmer/go-junit-report/v2@latest + cd integrationTests/tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}integration_junit_report.xml -set-exit-code + + + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 15m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4828e0e --- /dev/null +++ b/Readme.md @@ -0,0 +1,1145 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Integrations](#integrations) + - [MariaDB](#mariadb) + - [Example usage](#mariadb-usage-example) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate and `keypath` with local PATH to the key. +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for Certificate authorization**: +```shell +$ vault write securosys-hsm/config +auth="CERT" +certpath="local_absolute_path_to_certificate.pem" +keypath="local_absolute_path_to_private.key" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=CERT' \ +--data-urlencode 'certpath=local_absolute_path_to_certificate.pem' \ +--data-urlencode 'keypath=local_absolute_path_to_private.pem' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Integrations +### MariaDB +Encryption on MariaDB can be enabled using existing plugin [Hashicorp Key Management Plugin](https://mariadb.com/kb/en/hashicorp-key-management-plugin/) +This integration stores generated secret in Secrets engine, encrypted by provided key. +**Supported Key Types**/**Algorithm** combinations: +| Key Type | Algorithm | +|----------|:-------------:| +| **RSA** |RSA_PADDING_OAEP_WITH_SHA512
RSA
RSA_PADDING_OAEP_WITH_SHA224
RSA_PADDING_OAEP_WITH_SHA256
RSA_PADDING_OAEP_WITH_SHA1
RSA_PADDING_OAEP
RSA_PADDING_OAEP_WITH_SHA384
RSA_NO_PADDING| +|**AES**|AES_GCM
AES_CTR
AES_ECB
AES_CBC_NO_PADDING
AES | +| **CHACHA20** | CHACHA20
CHACHA20_AEAD| +| **CAMELLIA** | CAMELLIA
CAMELLIA_CBC_NO_PADDING
CAMELLIA_ECB | +|**TDEA**| TDEA_CBC
TDEA_ECB
TDEA_CBC_NO_PADDING | + +>**Note** - Plugin supports **asynchronous decrypt operation** using key type **RSA** with **policy** with setup **ruleUse**. Using the key with policy will **stop** the decrypt operation and **wait for approvals** to be collected. + +There are a **serval steps** that is needed to be done before setup encryption on MariaDB +1) [Create / Register key](#manage-keys) into **Secrets Engine** +1) Generate new **secret** and encrypt it using stored key + ```shell + $ vault write securosys-hsm/integrations/mariadb/{secret-name} + keyName={key-name-from-secret-engine} + cipherAlgorithm={cipher-algorithm} + [additionalAuthenticationData={additional-authentication-data}] + [tagLength={tag-length}] + [password={password-for-a-key}] + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/integrations/mariadb/{secret-name} ' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName={key-name-from-secret-engine}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + >**Note** - Every request on this endpoint using same **key name** and **secret name** will **rotate secret** +1) The last step is add this configuration to **my.cfg** + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" + loose-hashicorp-key-management-token="{vault_access_token}" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + >**Note** - In **loose-hashicorp-key-management-vault-url** url need to ends with **&version=**. Plugin from **MariaDB** automatically add to end of url **number of secret version** +#### MariaDB usage example +This example using default configuration for **Hashicorp Vault dev server**. +| Data | Value | +|----------|:-------------:| +| **vault address** | https://localhost:8200 | +| **vault access token** | root | +1) **Create key** *MariaDBEncryptionKey* with key size *4096* with attributes at last "decrypt" equals *true* on HSM and store it as *mariadb_encryption_key* on **Secrets engine** + ```shell + $ vault write securosys-hsm/keys/rsa/mariadb_encryption_key + keyLabel="MariaDBEncryptionKey" + keySize=4096 + attributes='{"decrypt": true,"sign": false,"unwrap": false,"derive": true,"sensitive": true,"extractable": false,"modifiable": false,"copyable": false,"destroyable": true}' + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/keys/rsa/mariadb_encryption_key' \ + --header 'X-Vault-Token: root' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel=MariaDBEncryptionKey' \ + --data-urlencode 'keySize=4096' \ + --data-urlencode 'attributes={ + "decrypt": true, + "sign": false, + "unwrap": false, + "derive": true, + "sensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": false, + "copyable": false, + "destroyable": true + }' + ``` +1) Generate new **secret** called *mariadb_secret* and **encrypt it** using cipher algorithm *RSA* and stored key *mariadb_encryption_key* in **Secrets engine** + ```shell + $ vault write securosys-hsm/integrations/mariadb/mariadb_secret + keyName=mariadb_encryption_key + cipherAlgorithm=RSA + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret ' \ + --header 'X-Vault-Token: root' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName=mariadb_encryption_key' \ + --data-urlencode 'cipherAlgorithm=RSA' + ``` +3. Configure **MariaDB plugin** "Hashicorp Key Management" in database configuration in **my.cnf** + + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret/?key_name=mariadb_encryption_key&cipher_algorithm=RSA&version=" + loose-hashicorp-key-management-token="root" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + + + +--- +## Appendix +### Frequently Asked Questions +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..67cf38a --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,140 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + pathMariaDBIntegration(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..29a1fac --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,294 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "keypath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to key", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "KeyPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if keypath, ok := data.GetOk("keypath"); ok { + config.KeyPath = keypath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing keypath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.KeyPath) + + if err != nil { + return nil, fmt.Errorf("Keypath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..8281fe0 --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,452 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..32954d9 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string), map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy, map[string]string{}) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil, map[string]string{}) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString, nil) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..e24fe58 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} diff --git a/backend/path_mariadb_integration.go b/backend/path_mariadb_integration.go new file mode 100644 index 0000000..0101c1d --- /dev/null +++ b/backend/path_mariadb_integration.go @@ -0,0 +1,666 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for create Camellia Keys +func pathMariaDBIntegration(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "keyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsDelete, + }, + }, + HelpSynopsis: pathIntegrationMariaDBWriteHelpSynopsis, + HelpDescription: pathIntegrationMariaDBWriteHelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("version") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV1HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV1HelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV2HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV2HelpDescription, + }, + { + Pattern: "integrations/mariadb/?$", + Fields: map[string]*framework.FieldSchema{}, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsList, + }, + }, + HelpSynopsis: pathIntegrationMariaDBListHelpSynopsis, + HelpDescription: pathIntegrationMariaDBListHelpDescription, + }, + } +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "intergration/mariadb/") + if err != nil { + return nil, err + } + secrets := make([]string, 0, len(entries)) + secretsInfo := make(map[string]interface{}) + for _, name := range entries { + secrets = append(secrets, name) + secret, err := b.GetMariaDBSecret(ctx, req.Storage, name) + if err == nil { + secretsInfo[name] = map[string]interface{}{ + "KeyName": secret.KeyName, + "Version": secret.CurrentVersion, + "Created": secret.Created.Name, + "Updated": secret.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(secrets, secretsInfo), nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, errGet := b.GetMariaDBSecret(ctx, req.Storage, name) + if errGet != nil { + return nil, fmt.Errorf("error deleting mariadb secret: %w", errGet) + } + if storedSecret == nil { + return nil, fmt.Errorf("error deleting mariadb secret: secret with name %s not exists", d.Get("name").(string)) + + } + + err := req.Storage.Delete(ctx, "intergration/mariadb/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + rotate := false + if storedSecret != nil { + rotate = true + // return nil, fmt.Errorf("error secret with name: %s exists", name) + } else { + storedSecret = &helpers.MariaDBSecretEntry{} + + } + + keyName := d.Get("keyName").(string) + + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload := b64.StdEncoding.EncodeToString([]byte(helpers.GeneratePassword(32, false, false, false, true))) + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + sysView := b.System() + creator := helpers.Entity{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + creator.Aliases = entity.Aliases + creator.Id = entity.ID + creator.Name = entity.Name + creator.Date = time.Now().UTC() + + } else { + creator.Aliases = nil + creator.Id = "root" + creator.Name = "root" + creator.Date = time.Now().UTC() + + } + var messageAuthenticationCode *string = nil + if result["messageAuthenticationCode"] != nil { + temp := result["messageAuthenticationCode"].(string) + messageAuthenticationCode = &temp + } + var initializationVector *string = nil + if result["initializationVector"] != nil { + temp := result["initializationVector"].(string) + initializationVector = &temp + } + if !rotate { + storedSecret.InitSecret(keyName, keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + } else { + storedSecret.RotateSecret(keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + + } + if err := SetMariaDBSecret(ctx, req.Storage, name, storedSecret); err != nil { + return nil, err + } + + response := map[string]interface{}{} + now := storedSecret.GetActiveVersion().Created.Date + version := storedSecret.GetActiveVersion().Version + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + query := d.Get("query").(string) + if strings.HasPrefix(query, "?") { + query = query[1:] + } + params, err := url.ParseQuery(query) + + if query == "" { + str := "" + for key, value := range req.Data { + str = str + key + "=" + value.(string) + "&" + } + str = str[:len(str)-1] + params, err = url.ParseQuery(str) + } + + if err != nil { + return nil, err + } + name := d.Get("name").(string) + + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + if storedSecret == nil { + return nil, fmt.Errorf("error secret with name: %s not exists", name) + } + + version := "1" + if params.Has("version") { + if !strings.Contains(params.Get("version"), "?version=") { + version = storedSecret.CurrentVersion + } else { + parts := strings.Split(params.Get("version"), "?version=") + version = "v" + parts[1] + } + } else { + ver, ok := d.GetOk("version") + if !ok { + return nil, fmt.Errorf("error: missing version") + } + version = ver.(string) + } + + if !params.Has("key_name") { + return nil, fmt.Errorf("key_name query param not exists") + } + keyEntry, err := b.GetKey(ctx, req.Storage, params.Get("key_name")) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + keyName := params.Get("key_name") + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + + if !helpers.ContainsKey(storedSecret.Versions, version) { + return nil, fmt.Errorf("Secret version %s is not exists.", version) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload := storedSecret.GetVersion(version).EncryptedSecret + + if !params.Has("cipher_algorithm") { + return nil, fmt.Errorf("cipher_algorithm query param not exists") + } + + cipherAlgorithm := params.Get("cipher_algorithm") + if keyEntry.KeyTypeName != "aes256-gcm96" && cipherAlgorithm == "" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVectorString := "" + if params.Has("initialization_vector") { + initializationVectorString = params.Get("initialization_vector") + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + passwordString := "" + if params.Has("password") { + passwordString = params.Get("password") + } + tagLengthInt := -1 + if params.Has("tag_length") { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + } + if keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationDataString := "" + if params.Has("aad") { + additionalAuthenticationDataString = params.Get("aad") + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationDataString) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData (param aad) is not valid base64 string") + } + } + client, err := b.GetClient(ctx, req.Storage) + async := false + decrypted := "" + if len(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + async = true + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString, map[string]string{"integration": "MariaDB Encrypt"}) + if errEnc != nil { + return nil, errEnc + } + var resp *helpers.RequestResponse + resp, _, _ = client.GetRequest(requestId) + for resp.Status == "PENDING" { + time.Sleep(1000) + resp, _, _ = client.GetRequest(requestId) + } + if resp.Status != "EXECUTED" { + return nil, fmt.Errorf("error on async decrypt. Expected Status '%s' got '%s'", "EXECUTED", resp.Status) + } + decrypted = resp.Result + + } + } + } + if !async { + resultSync, errEnc := client.Decrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + decrypted = resultSync["payload"].(string) + } + + if cipherAlgorithm == "AES_ECB" || + cipherAlgorithm == "AES_CBC_NO_PADDING" || + cipherAlgorithm == "CAMELLIA_ECB" || + cipherAlgorithm == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + decoded, _ := base64.StdEncoding.DecodeString(decrypted) + response := map[string]interface{}{} + response["data"] = map[string]interface{}{"data": string(decoded)} + now := storedSecret.GetVersion(version).Created.Date + + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} + +// This function helps with saving key in Secrets Engine +func SetMariaDBSecret(ctx context.Context, s logical.Storage, name string, secretEntry *helpers.MariaDBSecretEntry) error { + entry, err := logical.StorageEntryJSON("intergration/mariadb/"+name, secretEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage secret") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetMariaDBSecret(ctx context.Context, s logical.Storage, name string) (*helpers.MariaDBSecretEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "intergration/mariadb/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var secret helpers.MariaDBSecretEntry + + if err := entry.DecodeJSON(&secret); err != nil { + return nil, err + } + return &secret, nil +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..b50c7e2 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1023 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + KeyPath: data["keypath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + ` + passwordString + ` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy, customMetaData map[string]string) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo, customMetaData) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString := "" + if len(keyToBeWrappedPasswordJson) > 2 { + keyToBeWrappedPasswordString = `"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString := "" + if len(wrapKeyPasswordJson) > 2 { + wrapKeyPasswordString = `"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + ` + keyToBeWrappedPasswordString + ` + "wrapKeyName": "` + wrapKeyName + `", + ` + wrapKeyPasswordString + ` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + ` + passwordString + ` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + ` + passwordString + ` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + ` + passwordString + ` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + ` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString := "" + if len(charsNewPasswordJson) > 2 { + newPasswordString = `"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + newPasswordString + ` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + passwordString + ` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + clientTLSCert, err := tls.LoadX509KeyPair(c.Auth.CertPath, c.Auth.KeyPath) + if err != nil { + log.Fatalf("Error loading certificate and key file: %v", err) + return nil, err, 0 + } + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + InsecureSkipVerify: true, + Certificates: []tls.Certificate{clientTLSCert}, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/docker-builder/alpine3/docker-compose-alpine3.yml b/docker-builder/alpine3/docker-compose-alpine3.yml new file mode 100644 index 0000000..1190d88 --- /dev/null +++ b/docker-builder/alpine3/docker-compose-alpine3.yml @@ -0,0 +1,56 @@ + version: "3.3" + services: + golang-builder-alpine3-amd64: + platform: linux/amd64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=amd64 + image: amd64/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-amd64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-i386: + platform: linux/i386 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=386 + image: i386/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-i386 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-arm64: + platform: linux/arm64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=arm64 + image: arm64v8/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-arm64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" \ No newline at end of file diff --git a/docker-builder/build-in-docker.sh b/docker-builder/build-in-docker.sh new file mode 100644 index 0000000..adc15b2 --- /dev/null +++ b/docker-builder/build-in-docker.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd .. +echo "Build ${ARTIFACT_NAME} in ${DOCKER_OS}_${DOCKER_ARCH}"; + cd /src + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; + cd builds; + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; + zip -9 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; + shasum -a 256 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; + cd ..; + rm builds/securosys-hsm; + rm builds/securosys-hsm_SHA256SUM; \ No newline at end of file diff --git a/etc/example/mariaDb.cfg b/etc/example/mariaDb.cfg new file mode 100644 index 0000000..298e73a --- /dev/null +++ b/etc/example/mariaDb.cfg @@ -0,0 +1,22 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" +loose-hashicorp-key-management-token="{vault_access_token}" +loose-hashicorp-key-management-check-kv-version="off" +#max timeout is 86400 seconds +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +#1 year in miliseconds +loose-hashicorp-key-management-cache-timeout=31556952000 +#1 year in miliseconds +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +#Example of innodb config +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = ON +innodb_encrypt_log = ON +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 \ No newline at end of file diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..8e00e02 --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,93 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..6eebb05 --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,29 @@ +# Securosys Hashicorp Vault Secrets Engine 1.1.0 +Issued: Dec, 6, 2023 +## Documentation Change +- Update Readme.md - added information about supporting and how to configure encryption on MariaDB +## Feature +- Added integration with MariaDB encryption +## Bugfix +- Fixed authentication with TSB using mTLS + +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build/ + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2d78c0c --- /dev/null +++ b/go.mod @@ -0,0 +1,80 @@ +module secretengine + +go 1.21 + +toolchain go1.21.2 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers + +replace securosys.ch/tests => ./tests + +replace securosys.ch/integration/client => ./integrationTests/client + +replace securosys.ch/integration/tests => ./integrationTests/tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/frankban/quicktest v1.14.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afae25d --- /dev/null +++ b/go.sum @@ -0,0 +1,254 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work new file mode 100644 index 0000000..ad36518 --- /dev/null +++ b/go.work @@ -0,0 +1,8 @@ +go 1.21 + +use ( + ./ + ./backend + ./integrationTests/client + ./integrationTests/tests +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..976ca94 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,164 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..bdc47e4 --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "math/rand" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} +func GetVersionNumber(version string) int { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + return versionInt +} +func GetVersionString(version string) string { + return strings.Replace(version, "v", "", 1) +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string, customMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + for key, value := range customMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + specialBytes = "!@#$%^&*()_+-=[]{}\\|;':\",.<>/?`~" + numBytes = "0123456789" + hexDecimalBytes = "0123456789ABCDEF" +) + +func GeneratePassword(length int, useLetters bool, useSpecial bool, useNum bool, useHexadecimal bool) string { + rand.Seed(time.Now().UnixNano()) + b := make([]byte, length) + arrayForRandom := make([]byte, 0) + if useLetters { + arrayForRandom = append(arrayForRandom, letterBytes...) + } + if useSpecial { + arrayForRandom = append(arrayForRandom, specialBytes...) + } + if useNum { + arrayForRandom = append(arrayForRandom, numBytes...) + } + if useHexadecimal { + arrayForRandom = append(arrayForRandom, hexDecimalBytes...) + + } + + for i := range b { + b[i] = arrayForRandom[rand.Intn(len(arrayForRandom))] + } + return string(b) +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/mariadb_structs.go b/helpers/mariadb_structs.go new file mode 100644 index 0000000..97210ac --- /dev/null +++ b/helpers/mariadb_structs.go @@ -0,0 +1,82 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// INTEGRATION MARIADB STRUCTS + +type MariaDBSecretEntry struct { + KeyName string `json:"keyName"` + Versions map[string]MariaDBSecretVersion `json:"secretVersions"` + CurrentVersion string `json:"defaultVersion"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +// Struct of keys stored inside the Vault +type MariaDBSecretVersion struct { + KeyVersion string `json:"keyVersion"` + EncryptedSecret string `json:"encryptedSecret"` + MessageAuthenticationCode *string `json:"messageAuthenticationCode"` + InitializationVector *string `json:"initializationVector"` + Version string `json:"version"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (s *MariaDBSecretEntry) InitSecret(keyName string, keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, creator Entity) { + s.CurrentVersion = "v1" + s.KeyName = keyName + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = "v1" + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = creator + secretVersion.Updated = creator + s.Created = creator + s.Updated = creator + s.Versions = make(map[string]MariaDBSecretVersion) + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) RotateSecret(keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, updater Entity) { + newSecretVersion := GetNewVersion(s.CurrentVersion) + s.CurrentVersion = newSecretVersion + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = newSecretVersion + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = updater + secretVersion.Updated = updater + s.Updated = updater + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) GetActiveVersion() MariaDBSecretVersion { + return s.Versions[s.CurrentVersion] +} +func (s *MariaDBSecretEntry) GetVersion(keyVersion string) MariaDBSecretVersion { + return s.Versions[keyVersion] +} + +// END INTEGRATION MARIADB STRUCTS diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9782f2d --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,316 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/integrationTests/client/client.go b/integrationTests/client/client.go new file mode 100644 index 0000000..70d4bee --- /dev/null +++ b/integrationTests/client/client.go @@ -0,0 +1,30 @@ +package integrationClient + +import ( + "fmt" + "log" + "os" + "time" + + "github.com/hashicorp/vault-client-go" +) + +func InitVaultClient() (*vault.Client){ + + // prepare a client with the given base address + client, err := vault.New( + vault.WithAddress(VaultConfig.Url+":"+fmt.Sprint(VaultConfig.Port)), + vault.WithRequestTimeout(30*time.Second), + ) + if err != nil { + log.Fatal(err) + os.Exit(1); + } + + // authenticate with a root token (insecure) + if err := client.SetToken(VaultConfig.RootToken); err != nil { + log.Fatal(err) + os.Exit(1); + } + return client; +} \ No newline at end of file diff --git a/integrationTests/client/client_config.go b/integrationTests/client/client_config.go new file mode 100644 index 0000000..148f2a9 --- /dev/null +++ b/integrationTests/client/client_config.go @@ -0,0 +1,15 @@ +package integrationClient + +type VaultClientConfig struct { + Port int + Url string + RootToken string + SecretsEnginePath string +} + +var VaultConfig VaultClientConfig=VaultClientConfig{ + Port: 8251, + Url: "http://127.0.0.1", + RootToken: "root", + SecretsEnginePath: "securosys-hsm", +} \ No newline at end of file diff --git a/integrationTests/client/go.mod b/integrationTests/client/go.mod new file mode 100644 index 0000000..02d12cd --- /dev/null +++ b/integrationTests/client/go.mod @@ -0,0 +1,24 @@ +module securosys.ch/integration/client + +go 1.21 + +toolchain go1.21.2 + +require github.com/hashicorp/vault-client-go v0.4.2 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stretchr/testify v1.8.2 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect +) diff --git a/integrationTests/client/go.sum b/integrationTests/client/go.sum new file mode 100644 index 0000000..3a52bd0 --- /dev/null +++ b/integrationTests/client/go.sum @@ -0,0 +1,58 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/vault-client-go v0.4.2 h1:XeUXb5jnDuCUhC8HRpkdGPLh1XtzXmiOnF0mXEbARxI= +github.com/hashicorp/vault-client-go v0.4.2/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integrationTests/docker/docker-compose.yml b/integrationTests/docker/docker-compose.yml new file mode 100644 index 0000000..1b00ff4 --- /dev/null +++ b/integrationTests/docker/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.0" +name: hashicorp-vault-test-containers +services: + hashicorp-vault-test: + image: hashicorp/vault:latest + container_name: "hashicorp-vault-test" + environment: + VAULT_DEV_ROOT_TOKEN_ID: root + VAULT_ADDR: 'https://0.0.0.0:8251' + VAULT_LOCAL_CONFIG: '{"listener": [{"tcp":{"address": "0.0.0.0:8251","tls_disable":"1"}}], "default_lease_ttl": "168h", "max_lease_ttl": "720h"}, "ui": true}' + volumes: + - ./plugins/:/vault/plugins + cap_add: + - IPC_LOCK + healthcheck: + retries: 5 + ports: + - "8251:8251" + privileged: true + command: server -dev -dev-root-token-id=root -dev-plugin-dir=/vault/plugins + networks: + - web + mariadb-test-integration: + build: + dockerfile: ./docker-files/MariaDB_Dockerfile + container_name: "mariadb-test-integration" + restart: always + environment: + MARIADB_ROOT_PASSWORD: example + volumes: + - ./mysql-config:/etc/mysql/conf.d + - ./db:/var/lib/mysql + networks: + - web + +networks: + web: + external: true + \ No newline at end of file diff --git a/integrationTests/docker/docker-files/MariaDB_Dockerfile b/integrationTests/docker/docker-files/MariaDB_Dockerfile new file mode 100644 index 0000000..7e5d37a --- /dev/null +++ b/integrationTests/docker/docker-files/MariaDB_Dockerfile @@ -0,0 +1,2 @@ +FROM mariadb:latest +RUN apt-get update && apt-get install -y mariadb-plugin-hashicorp-key-management diff --git a/integrationTests/docker/mysql-config/hashicorp.cnf b/integrationTests/docker/mysql-config/hashicorp.cnf new file mode 100644 index 0000000..d628bc7 --- /dev/null +++ b/integrationTests/docker/mysql-config/hashicorp.cnf @@ -0,0 +1,18 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="http://192.168.96.3:8251/v1/securosys-hsm/integrations/mariadb/test_async/?cipher_algorithm=RSA&key_name=rsa_with_policy&version=" +loose-hashicorp-key-management-token="root" +loose-hashicorp-key-management-check-kv-version="off" +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +loose-hashicorp-key-management-cache-timeout=31556952000 +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = OFF +innodb_encrypt_log = OFF +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 diff --git a/integrationTests/tests/a_enable_plugin_test.go b/integrationTests/tests/a_enable_plugin_test.go new file mode 100644 index 0000000..d16575a --- /dev/null +++ b/integrationTests/tests/a_enable_plugin_test.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "testing" + + "github.com/hashicorp/vault-client-go/schema" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestEnablePlugin(t *testing.T) { + + t.Run("A.1 Test Enable Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.System.MountsEnableSecretsEngine(ctx,integrationClient.VaultConfig.SecretsEnginePath,schema.MountsEnableSecretsEngineRequest{ + Type: "securosys-hsm", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/b_config_plugin_test.go b/integrationTests/tests/b_config_plugin_test.go new file mode 100644 index 0000000..d777766 --- /dev/null +++ b/integrationTests/tests/b_config_plugin_test.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfigPlugin(t *testing.T) { + + t.Run("B.1 Test Config Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/config",testHelpers.ConfigParams) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data["result"]==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s","null").Error()) + } + + if(!strings.Contains(resp.Data["result"].(string),"Connection successful:")){ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s",resp.Data["result"]).Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_aes_key_test.go b/integrationTests/tests/c_create_aes_key_test.go new file mode 100644 index 0000000..ccffd1b --- /dev/null +++ b/integrationTests/tests/c_create_aes_key_test.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateAESKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_aes"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_aes got %s","null").Error()) + } + }) + t.Run("C.3 Read AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["secretKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Key Secret got %s","null").Error()) + } + }) + t.Run("C.8 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_key_by_keyname_test.go b/integrationTests/tests/c_create_key_by_keyname_test.go new file mode 100644 index 0000000..285e47c --- /dev/null +++ b/integrationTests/tests/c_create_key_by_keyname_test.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateKeyByKeyNamePlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with label integrationTestKeyRSAName using name rsa-2048", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/type/rsa-2048/integration_test_key_rsa_name",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSAName", + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSAName"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSAName",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSAName_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test Remove Key RSA Key with name integrationTestKeyRSAName", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa_name",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_rsa_key_test.go b/integrationTests/tests/c_create_rsa_key_test.go new file mode 100644 index 0000000..90c1a10 --- /dev/null +++ b/integrationTests/tests/c_create_rsa_key_test.go @@ -0,0 +1,250 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["publicKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Public Key got %s","null").Error()) + } + if(resp.Data["privateKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Private Key got %s","null").Error()) + } + }) + t.Run("C.8 Update password RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/update-password",map[string]interface{}{ + "password":"", + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Test Remove Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_smart_rsa_key_test.go b/integrationTests/tests/c_create_smart_rsa_key_test.go new file mode 100644 index 0000000..dfdd792 --- /dev/null +++ b/integrationTests/tests/c_create_smart_rsa_key_test.go @@ -0,0 +1,255 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateSmartRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_smart_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_smart_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Block Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/block",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.8 UnBlock Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/unblock",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Update password Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/update-password",map[string]interface{}{ + "password":nil, + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/d_operations_on_key_test.go b/integrationTests/tests/d_operations_on_key_test.go new file mode 100644 index 0000000..8dc951b --- /dev/null +++ b/integrationTests/tests/d_operations_on_key_test.go @@ -0,0 +1,329 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestOperationsOnKeyPlugin(t *testing.T) { + + t.Run("D.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.2 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.3 Test Encrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.4 Test Encrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.5 Test Decrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.6 Test Decrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_key_aes",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.7 Test Sign using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + }) + t.Run("D.8 Test Verify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/verify/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "keyVersion":"v1", + "signatureAlgorithm":"SHA256_WITH_RSA", + "signature":resp.Data["signature"].(string), + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid got %s","null").Error()) + } + if(resp.Data["signatureValid"]==false){ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid %s got %s","true",resp.Data["signatureValid"]).Error()) + } + }) + t.Run("D.9 Test Modify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/modify",map[string]interface{}{ + "simplePolicy":`{"test":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnydX62tLYNF+Op1SRnX6avkkyQWlpYPagH85zxaGnMlZoMioqgjSOCuRvjaP7Y5noPMYayp3gJ2PwLXvw9+JlnL+iwklOcpONSa6gDoCDsk26DOoY0ELEPaGdW61mc2bj2hOQE0GEpPsRywJoRLS3B2e8bqRfAniAfGsUq3MK09iL5YOCuUCHCUiR9iZMSt0+Ek/kE4TrazbOCev1g6Ux2vOyTuQ6mF3wVuqwd8RhfvlNNKXbD2GD/jR3BwuhaodwzRPmDyDQPmEMwornxrMLavTcC+Igb4k5qol0Di6Oq8axpBvrH7KlxHT11Wd+ALKCsqoPSGxcIbd6TdN+ag9AQIDAQAB"}`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.11 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/go.mod b/integrationTests/tests/go.mod new file mode 100644 index 0000000..02bc999 --- /dev/null +++ b/integrationTests/tests/go.mod @@ -0,0 +1,6 @@ +module securosys.ch/integration/tests + +replace securosys.ch/integration/client => ./../client +replace securosys.ch/test-helpers => ./../../testHelpers + +go 1.19 diff --git a/integrationTests/tests/go.sum b/integrationTests/tests/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..0111058 --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.1.0 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..b55e030 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_API_URL", + "auth": "TOKEN", + "bearertoken": "TSB_BEARER_TOKEN", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/go.work b/tests/go.work new file mode 100644 index 0000000..7c33c4f --- /dev/null +++ b/tests/go.work @@ -0,0 +1,5 @@ +go 1.21 + +use ( + ./ +) \ No newline at end of file diff --git a/tests/go.work.sum b/tests/go.work.sum new file mode 100644 index 0000000..aff7933 --- /dev/null +++ b/tests/go.work.sum @@ -0,0 +1,163 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} diff --git a/tests/path_mariadb_integration_test.go b/tests/path_mariadb_integration_test.go new file mode 100644 index 0000000..b9b856e --- /dev/null +++ b/tests/path_mariadb_integration_test.go @@ -0,0 +1,111 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIntegrationMariaDB(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("A) add config", testEnv.AddConfig) + + t.Run("B) Test Creating RSA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + }) + t.Run("C)Add generate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("D)Read secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "integrations/mariadb/test/v1?key_name=custom_rsa_2048&cipher_algorithm=RSA", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("E) Rotate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("F) List secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "integrations/mariadb", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("G) Delete secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "integrations/mariadb/test", + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("H) Test Delete RSA key", func(t *testing.T) { + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + assert.NoError(t, err) + }) +} From 93f568e08d0f08365c72ef9b80cffa20b08af641 Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Wed, 31 Jan 2024 10:21:49 +0100 Subject: [PATCH 13/16] Release v.1.1.0 --- .github/ISSUE_TEMPLATE/bug-report-sse.md | 49 + .github/ISSUE_TEMPLATE/feature-request-sse.md | 33 + .gitignore | 4 + LICENSE | 201 ++ Makefile | 201 ++ Readme.md | 1145 ++++++++++++ backend/backend.go | 140 ++ backend/go.mod | 62 + backend/go.sum | 223 +++ backend/path_config.go | 294 +++ backend/path_help.go | 452 +++++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 +++ backend/path_hsm_key_bls.go | 259 +++ backend/path_hsm_key_camellia.go | 225 +++ backend/path_hsm_key_chacha20.go | 208 +++ backend/path_hsm_key_dsa.go | 273 +++ backend/path_hsm_key_ec.go | 270 +++ backend/path_hsm_key_ed.go | 271 +++ backend/path_hsm_key_import.go | 306 ++++ backend/path_hsm_key_rsa.go | 273 +++ backend/path_hsm_key_tdea.go | 208 +++ backend/path_hsm_key_with_name.go | 295 +++ backend/path_hsm_keys.go | 1359 ++++++++++++++ backend/path_hsm_operations.go | 1631 +++++++++++++++++ backend/path_hsm_requests.go | 298 +++ backend/path_mariadb_integration.go | 666 +++++++ client/client.go | 48 + client/client_tsb.go | 1023 +++++++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + .../alpine3/docker-compose-alpine3.yml | 56 + docker-builder/build-in-docker.sh | 12 + etc/example/mariaDb.cfg | 22 + etc/example/policy.json | 93 + etc/release_notes/Release_Notes.md | 29 + go.mod | 80 + go.sum | 254 +++ go.work | 8 + go.work.sum | 164 ++ helpers/consts.go | 53 + helpers/functions.go | 234 +++ helpers/go.mod | 57 + helpers/go.sum | 223 +++ helpers/mariadb_structs.go | 82 + helpers/structs.go | 316 ++++ integrationTests/client/client.go | 30 + integrationTests/client/client_config.go | 15 + integrationTests/client/go.mod | 24 + integrationTests/client/go.sum | 58 + integrationTests/docker/docker-compose.yml | 39 + .../docker/docker-files/MariaDB_Dockerfile | 2 + .../docker/mysql-config/hashicorp.cnf | 18 + .../tests/a_enable_plugin_test.go | 48 + .../tests/b_config_plugin_test.go | 55 + .../tests/c_create_aes_key_test.go | 234 +++ .../tests/c_create_key_by_keyname_test.go | 93 + .../tests/c_create_rsa_key_test.go | 250 +++ .../tests/c_create_smart_rsa_key_test.go | 255 +++ .../tests/d_operations_on_key_test.go | 329 ++++ integrationTests/tests/go.mod | 6 + integrationTests/tests/go.sum | 0 project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 +++ testHelpers/test_client_tsb.go | 151 ++ testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 ++++++++ tests/go.mod | 66 + tests/go.sum | 223 +++ tests/go.work | 5 + tests/go.work.sum | 163 ++ tests/path_config_test.go | 153 ++ tests/path_hsm_key_aes_test.go | 133 ++ tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 ++ tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 ++ tests/path_hsm_key_tdea_test.go | 136 ++ tests/path_hsm_key_using_type_name_test.go | 245 +++ tests/path_hsm_keys_rotation_test.go | 836 +++++++++ tests/path_hsm_keys_test.go | 312 ++++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++++ tests/path_hsm_operations_sign_test.go | 647 +++++++ tests/path_hsm_operations_unwrap_test.go | 675 +++++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++++++++ tests/path_hsm_operations_wrap_test.go | 242 +++ tests/path_hsm_requests_test.go | 299 +++ tests/path_mariadb_integration_test.go | 111 ++ 95 files changed, 23286 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-sse.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-sse.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 backend/path_mariadb_integration.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 docker-builder/alpine3/docker-compose-alpine3.yml create mode 100644 docker-builder/build-in-docker.sh create mode 100644 etc/example/mariaDb.cfg create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 go.work create mode 100644 go.work.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/mariadb_structs.go create mode 100644 helpers/structs.go create mode 100644 integrationTests/client/client.go create mode 100644 integrationTests/client/client_config.go create mode 100644 integrationTests/client/go.mod create mode 100644 integrationTests/client/go.sum create mode 100644 integrationTests/docker/docker-compose.yml create mode 100644 integrationTests/docker/docker-files/MariaDB_Dockerfile create mode 100644 integrationTests/docker/mysql-config/hashicorp.cnf create mode 100644 integrationTests/tests/a_enable_plugin_test.go create mode 100644 integrationTests/tests/b_config_plugin_test.go create mode 100644 integrationTests/tests/c_create_aes_key_test.go create mode 100644 integrationTests/tests/c_create_key_by_keyname_test.go create mode 100644 integrationTests/tests/c_create_rsa_key_test.go create mode 100644 integrationTests/tests/c_create_smart_rsa_key_test.go create mode 100644 integrationTests/tests/d_operations_on_key_test.go create mode 100644 integrationTests/tests/go.mod create mode 100644 integrationTests/tests/go.sum create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/go.work create mode 100644 tests/go.work.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go create mode 100644 tests/path_mariadb_integration_test.go diff --git a/.github/ISSUE_TEMPLATE/bug-report-sse.md b/.github/ISSUE_TEMPLATE/bug-report-sse.md new file mode 100644 index 0000000..40777e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-sse.md @@ -0,0 +1,49 @@ +--- +name: Bug report SSE +about: Create a report to help us improve +title: "[BUG] " +labels: '' +assignees: Peter-FNet + +--- + + + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment:** +* Vault Server Version (retrieve with `vault status`): +* Vault CLI Version (retrieve with `vault version`): +* Server Operating System/Architecture: + +Vault server configuration file(s): + +```hcl +# Paste your Vault config here. +# Be sure to scrub any sensitive values +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request-sse.md b/.github/ISSUE_TEMPLATE/feature-request-sse.md new file mode 100644 index 0000000..8264e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-sse.md @@ -0,0 +1,33 @@ +--- +name: Feature request SSE +about: Suggest an idea for this project +title: "[FEAT]" +labels: '' +assignees: Peter-FNet + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Explain any additional use-cases** +If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5375b60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +builds +vault +deploy +.gitlab-ci.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a142d1d --- /dev/null +++ b/Makefile @@ -0,0 +1,201 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` + +ifndef ARTIFACT_NAME +override ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +endif + +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + make release-alpine3 + echo "Finished!"; + +release-alpine3: + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-amd64 + make clean-docker-builder IMAGE=amd64/golang + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-i386 + make clean-docker-builder IMAGE=i386/golang + +clean-docker-builder: + @if [ "$$(docker images | grep '$(IMAGE)')" != "" ]; then \ + docker rmi -f $$(docker images | grep '$(IMAGE)' | awk '{ print $$3}') 2> /dev/null || true ; \ + fi; + docker volume prune -f + docker container prune -f + docker network prune -f + +run-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml up --build -d +clean-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml down --remove-orphans --rmi all + docker volume prune -f + docker container prune -f +integration-tests: + rm -fr integrationTests/docker/plugins/securosys-hsm + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -o integrationTests/docker/plugins/securosys-hsm cmd/securosys-hsm/main.go + make run-docker-test-container + + sleep 5 + go install github.com/jstemmer/go-junit-report/v2@latest + cd integrationTests/tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}integration_junit_report.xml -set-exit-code + + + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 15m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4828e0e --- /dev/null +++ b/Readme.md @@ -0,0 +1,1145 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Integrations](#integrations) + - [MariaDB](#mariadb) + - [Example usage](#mariadb-usage-example) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate and `keypath` with local PATH to the key. +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for Certificate authorization**: +```shell +$ vault write securosys-hsm/config +auth="CERT" +certpath="local_absolute_path_to_certificate.pem" +keypath="local_absolute_path_to_private.key" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=CERT' \ +--data-urlencode 'certpath=local_absolute_path_to_certificate.pem' \ +--data-urlencode 'keypath=local_absolute_path_to_private.pem' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Integrations +### MariaDB +Encryption on MariaDB can be enabled using existing plugin [Hashicorp Key Management Plugin](https://mariadb.com/kb/en/hashicorp-key-management-plugin/) +This integration stores generated secret in Secrets engine, encrypted by provided key. +**Supported Key Types**/**Algorithm** combinations: +| Key Type | Algorithm | +|----------|:-------------:| +| **RSA** |RSA_PADDING_OAEP_WITH_SHA512
RSA
RSA_PADDING_OAEP_WITH_SHA224
RSA_PADDING_OAEP_WITH_SHA256
RSA_PADDING_OAEP_WITH_SHA1
RSA_PADDING_OAEP
RSA_PADDING_OAEP_WITH_SHA384
RSA_NO_PADDING| +|**AES**|AES_GCM
AES_CTR
AES_ECB
AES_CBC_NO_PADDING
AES | +| **CHACHA20** | CHACHA20
CHACHA20_AEAD| +| **CAMELLIA** | CAMELLIA
CAMELLIA_CBC_NO_PADDING
CAMELLIA_ECB | +|**TDEA**| TDEA_CBC
TDEA_ECB
TDEA_CBC_NO_PADDING | + +>**Note** - Plugin supports **asynchronous decrypt operation** using key type **RSA** with **policy** with setup **ruleUse**. Using the key with policy will **stop** the decrypt operation and **wait for approvals** to be collected. + +There are a **serval steps** that is needed to be done before setup encryption on MariaDB +1) [Create / Register key](#manage-keys) into **Secrets Engine** +1) Generate new **secret** and encrypt it using stored key + ```shell + $ vault write securosys-hsm/integrations/mariadb/{secret-name} + keyName={key-name-from-secret-engine} + cipherAlgorithm={cipher-algorithm} + [additionalAuthenticationData={additional-authentication-data}] + [tagLength={tag-length}] + [password={password-for-a-key}] + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/integrations/mariadb/{secret-name} ' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName={key-name-from-secret-engine}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + >**Note** - Every request on this endpoint using same **key name** and **secret name** will **rotate secret** +1) The last step is add this configuration to **my.cfg** + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" + loose-hashicorp-key-management-token="{vault_access_token}" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + >**Note** - In **loose-hashicorp-key-management-vault-url** url need to ends with **&version=**. Plugin from **MariaDB** automatically add to end of url **number of secret version** +#### MariaDB usage example +This example using default configuration for **Hashicorp Vault dev server**. +| Data | Value | +|----------|:-------------:| +| **vault address** | https://localhost:8200 | +| **vault access token** | root | +1) **Create key** *MariaDBEncryptionKey* with key size *4096* with attributes at last "decrypt" equals *true* on HSM and store it as *mariadb_encryption_key* on **Secrets engine** + ```shell + $ vault write securosys-hsm/keys/rsa/mariadb_encryption_key + keyLabel="MariaDBEncryptionKey" + keySize=4096 + attributes='{"decrypt": true,"sign": false,"unwrap": false,"derive": true,"sensitive": true,"extractable": false,"modifiable": false,"copyable": false,"destroyable": true}' + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/keys/rsa/mariadb_encryption_key' \ + --header 'X-Vault-Token: root' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel=MariaDBEncryptionKey' \ + --data-urlencode 'keySize=4096' \ + --data-urlencode 'attributes={ + "decrypt": true, + "sign": false, + "unwrap": false, + "derive": true, + "sensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": false, + "copyable": false, + "destroyable": true + }' + ``` +1) Generate new **secret** called *mariadb_secret* and **encrypt it** using cipher algorithm *RSA* and stored key *mariadb_encryption_key* in **Secrets engine** + ```shell + $ vault write securosys-hsm/integrations/mariadb/mariadb_secret + keyName=mariadb_encryption_key + cipherAlgorithm=RSA + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret ' \ + --header 'X-Vault-Token: root' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName=mariadb_encryption_key' \ + --data-urlencode 'cipherAlgorithm=RSA' + ``` +3. Configure **MariaDB plugin** "Hashicorp Key Management" in database configuration in **my.cnf** + + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret/?key_name=mariadb_encryption_key&cipher_algorithm=RSA&version=" + loose-hashicorp-key-management-token="root" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + + + +--- +## Appendix +### Frequently Asked Questions +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..67cf38a --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,140 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + pathMariaDBIntegration(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..29a1fac --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,294 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "keypath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to key", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "KeyPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if keypath, ok := data.GetOk("keypath"); ok { + config.KeyPath = keypath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing keypath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.KeyPath) + + if err != nil { + return nil, fmt.Errorf("Keypath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..8281fe0 --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,452 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..32954d9 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string), map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy, map[string]string{}) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil, map[string]string{}) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString, nil) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..e24fe58 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} diff --git a/backend/path_mariadb_integration.go b/backend/path_mariadb_integration.go new file mode 100644 index 0000000..0101c1d --- /dev/null +++ b/backend/path_mariadb_integration.go @@ -0,0 +1,666 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for create Camellia Keys +func pathMariaDBIntegration(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "keyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsDelete, + }, + }, + HelpSynopsis: pathIntegrationMariaDBWriteHelpSynopsis, + HelpDescription: pathIntegrationMariaDBWriteHelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("version") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV1HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV1HelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV2HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV2HelpDescription, + }, + { + Pattern: "integrations/mariadb/?$", + Fields: map[string]*framework.FieldSchema{}, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsList, + }, + }, + HelpSynopsis: pathIntegrationMariaDBListHelpSynopsis, + HelpDescription: pathIntegrationMariaDBListHelpDescription, + }, + } +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "intergration/mariadb/") + if err != nil { + return nil, err + } + secrets := make([]string, 0, len(entries)) + secretsInfo := make(map[string]interface{}) + for _, name := range entries { + secrets = append(secrets, name) + secret, err := b.GetMariaDBSecret(ctx, req.Storage, name) + if err == nil { + secretsInfo[name] = map[string]interface{}{ + "KeyName": secret.KeyName, + "Version": secret.CurrentVersion, + "Created": secret.Created.Name, + "Updated": secret.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(secrets, secretsInfo), nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, errGet := b.GetMariaDBSecret(ctx, req.Storage, name) + if errGet != nil { + return nil, fmt.Errorf("error deleting mariadb secret: %w", errGet) + } + if storedSecret == nil { + return nil, fmt.Errorf("error deleting mariadb secret: secret with name %s not exists", d.Get("name").(string)) + + } + + err := req.Storage.Delete(ctx, "intergration/mariadb/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + rotate := false + if storedSecret != nil { + rotate = true + // return nil, fmt.Errorf("error secret with name: %s exists", name) + } else { + storedSecret = &helpers.MariaDBSecretEntry{} + + } + + keyName := d.Get("keyName").(string) + + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload := b64.StdEncoding.EncodeToString([]byte(helpers.GeneratePassword(32, false, false, false, true))) + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + sysView := b.System() + creator := helpers.Entity{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + creator.Aliases = entity.Aliases + creator.Id = entity.ID + creator.Name = entity.Name + creator.Date = time.Now().UTC() + + } else { + creator.Aliases = nil + creator.Id = "root" + creator.Name = "root" + creator.Date = time.Now().UTC() + + } + var messageAuthenticationCode *string = nil + if result["messageAuthenticationCode"] != nil { + temp := result["messageAuthenticationCode"].(string) + messageAuthenticationCode = &temp + } + var initializationVector *string = nil + if result["initializationVector"] != nil { + temp := result["initializationVector"].(string) + initializationVector = &temp + } + if !rotate { + storedSecret.InitSecret(keyName, keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + } else { + storedSecret.RotateSecret(keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + + } + if err := SetMariaDBSecret(ctx, req.Storage, name, storedSecret); err != nil { + return nil, err + } + + response := map[string]interface{}{} + now := storedSecret.GetActiveVersion().Created.Date + version := storedSecret.GetActiveVersion().Version + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + query := d.Get("query").(string) + if strings.HasPrefix(query, "?") { + query = query[1:] + } + params, err := url.ParseQuery(query) + + if query == "" { + str := "" + for key, value := range req.Data { + str = str + key + "=" + value.(string) + "&" + } + str = str[:len(str)-1] + params, err = url.ParseQuery(str) + } + + if err != nil { + return nil, err + } + name := d.Get("name").(string) + + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + if storedSecret == nil { + return nil, fmt.Errorf("error secret with name: %s not exists", name) + } + + version := "1" + if params.Has("version") { + if !strings.Contains(params.Get("version"), "?version=") { + version = storedSecret.CurrentVersion + } else { + parts := strings.Split(params.Get("version"), "?version=") + version = "v" + parts[1] + } + } else { + ver, ok := d.GetOk("version") + if !ok { + return nil, fmt.Errorf("error: missing version") + } + version = ver.(string) + } + + if !params.Has("key_name") { + return nil, fmt.Errorf("key_name query param not exists") + } + keyEntry, err := b.GetKey(ctx, req.Storage, params.Get("key_name")) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + keyName := params.Get("key_name") + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + + if !helpers.ContainsKey(storedSecret.Versions, version) { + return nil, fmt.Errorf("Secret version %s is not exists.", version) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload := storedSecret.GetVersion(version).EncryptedSecret + + if !params.Has("cipher_algorithm") { + return nil, fmt.Errorf("cipher_algorithm query param not exists") + } + + cipherAlgorithm := params.Get("cipher_algorithm") + if keyEntry.KeyTypeName != "aes256-gcm96" && cipherAlgorithm == "" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVectorString := "" + if params.Has("initialization_vector") { + initializationVectorString = params.Get("initialization_vector") + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + passwordString := "" + if params.Has("password") { + passwordString = params.Get("password") + } + tagLengthInt := -1 + if params.Has("tag_length") { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + } + if keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationDataString := "" + if params.Has("aad") { + additionalAuthenticationDataString = params.Get("aad") + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationDataString) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData (param aad) is not valid base64 string") + } + } + client, err := b.GetClient(ctx, req.Storage) + async := false + decrypted := "" + if len(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + async = true + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString, map[string]string{"integration": "MariaDB Encrypt"}) + if errEnc != nil { + return nil, errEnc + } + var resp *helpers.RequestResponse + resp, _, _ = client.GetRequest(requestId) + for resp.Status == "PENDING" { + time.Sleep(1000) + resp, _, _ = client.GetRequest(requestId) + } + if resp.Status != "EXECUTED" { + return nil, fmt.Errorf("error on async decrypt. Expected Status '%s' got '%s'", "EXECUTED", resp.Status) + } + decrypted = resp.Result + + } + } + } + if !async { + resultSync, errEnc := client.Decrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + decrypted = resultSync["payload"].(string) + } + + if cipherAlgorithm == "AES_ECB" || + cipherAlgorithm == "AES_CBC_NO_PADDING" || + cipherAlgorithm == "CAMELLIA_ECB" || + cipherAlgorithm == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + decoded, _ := base64.StdEncoding.DecodeString(decrypted) + response := map[string]interface{}{} + response["data"] = map[string]interface{}{"data": string(decoded)} + now := storedSecret.GetVersion(version).Created.Date + + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} + +// This function helps with saving key in Secrets Engine +func SetMariaDBSecret(ctx context.Context, s logical.Storage, name string, secretEntry *helpers.MariaDBSecretEntry) error { + entry, err := logical.StorageEntryJSON("intergration/mariadb/"+name, secretEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage secret") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetMariaDBSecret(ctx context.Context, s logical.Storage, name string) (*helpers.MariaDBSecretEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "intergration/mariadb/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var secret helpers.MariaDBSecretEntry + + if err := entry.DecodeJSON(&secret); err != nil { + return nil, err + } + return &secret, nil +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..b50c7e2 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1023 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + KeyPath: data["keypath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + ` + passwordString + ` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy, customMetaData map[string]string) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo, customMetaData) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString := "" + if len(keyToBeWrappedPasswordJson) > 2 { + keyToBeWrappedPasswordString = `"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString := "" + if len(wrapKeyPasswordJson) > 2 { + wrapKeyPasswordString = `"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + ` + keyToBeWrappedPasswordString + ` + "wrapKeyName": "` + wrapKeyName + `", + ` + wrapKeyPasswordString + ` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + ` + passwordString + ` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + ` + passwordString + ` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + ` + passwordString + ` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + ` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString := "" + if len(charsNewPasswordJson) > 2 { + newPasswordString = `"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + newPasswordString + ` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + passwordString + ` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + clientTLSCert, err := tls.LoadX509KeyPair(c.Auth.CertPath, c.Auth.KeyPath) + if err != nil { + log.Fatalf("Error loading certificate and key file: %v", err) + return nil, err, 0 + } + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + InsecureSkipVerify: true, + Certificates: []tls.Certificate{clientTLSCert}, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/docker-builder/alpine3/docker-compose-alpine3.yml b/docker-builder/alpine3/docker-compose-alpine3.yml new file mode 100644 index 0000000..1190d88 --- /dev/null +++ b/docker-builder/alpine3/docker-compose-alpine3.yml @@ -0,0 +1,56 @@ + version: "3.3" + services: + golang-builder-alpine3-amd64: + platform: linux/amd64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=amd64 + image: amd64/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-amd64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-i386: + platform: linux/i386 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=386 + image: i386/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-i386 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-arm64: + platform: linux/arm64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=arm64 + image: arm64v8/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-arm64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" \ No newline at end of file diff --git a/docker-builder/build-in-docker.sh b/docker-builder/build-in-docker.sh new file mode 100644 index 0000000..adc15b2 --- /dev/null +++ b/docker-builder/build-in-docker.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd .. +echo "Build ${ARTIFACT_NAME} in ${DOCKER_OS}_${DOCKER_ARCH}"; + cd /src + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; + cd builds; + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; + zip -9 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; + shasum -a 256 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; + cd ..; + rm builds/securosys-hsm; + rm builds/securosys-hsm_SHA256SUM; \ No newline at end of file diff --git a/etc/example/mariaDb.cfg b/etc/example/mariaDb.cfg new file mode 100644 index 0000000..298e73a --- /dev/null +++ b/etc/example/mariaDb.cfg @@ -0,0 +1,22 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" +loose-hashicorp-key-management-token="{vault_access_token}" +loose-hashicorp-key-management-check-kv-version="off" +#max timeout is 86400 seconds +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +#1 year in miliseconds +loose-hashicorp-key-management-cache-timeout=31556952000 +#1 year in miliseconds +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +#Example of innodb config +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = ON +innodb_encrypt_log = ON +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 \ No newline at end of file diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..8e00e02 --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,93 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..6eebb05 --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,29 @@ +# Securosys Hashicorp Vault Secrets Engine 1.1.0 +Issued: Dec, 6, 2023 +## Documentation Change +- Update Readme.md - added information about supporting and how to configure encryption on MariaDB +## Feature +- Added integration with MariaDB encryption +## Bugfix +- Fixed authentication with TSB using mTLS + +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build/ + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2d78c0c --- /dev/null +++ b/go.mod @@ -0,0 +1,80 @@ +module secretengine + +go 1.21 + +toolchain go1.21.2 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers + +replace securosys.ch/tests => ./tests + +replace securosys.ch/integration/client => ./integrationTests/client + +replace securosys.ch/integration/tests => ./integrationTests/tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/frankban/quicktest v1.14.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afae25d --- /dev/null +++ b/go.sum @@ -0,0 +1,254 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work new file mode 100644 index 0000000..ad36518 --- /dev/null +++ b/go.work @@ -0,0 +1,8 @@ +go 1.21 + +use ( + ./ + ./backend + ./integrationTests/client + ./integrationTests/tests +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..976ca94 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,164 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..bdc47e4 --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "math/rand" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} +func GetVersionNumber(version string) int { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + return versionInt +} +func GetVersionString(version string) string { + return strings.Replace(version, "v", "", 1) +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string, customMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + for key, value := range customMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + specialBytes = "!@#$%^&*()_+-=[]{}\\|;':\",.<>/?`~" + numBytes = "0123456789" + hexDecimalBytes = "0123456789ABCDEF" +) + +func GeneratePassword(length int, useLetters bool, useSpecial bool, useNum bool, useHexadecimal bool) string { + rand.Seed(time.Now().UnixNano()) + b := make([]byte, length) + arrayForRandom := make([]byte, 0) + if useLetters { + arrayForRandom = append(arrayForRandom, letterBytes...) + } + if useSpecial { + arrayForRandom = append(arrayForRandom, specialBytes...) + } + if useNum { + arrayForRandom = append(arrayForRandom, numBytes...) + } + if useHexadecimal { + arrayForRandom = append(arrayForRandom, hexDecimalBytes...) + + } + + for i := range b { + b[i] = arrayForRandom[rand.Intn(len(arrayForRandom))] + } + return string(b) +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/mariadb_structs.go b/helpers/mariadb_structs.go new file mode 100644 index 0000000..97210ac --- /dev/null +++ b/helpers/mariadb_structs.go @@ -0,0 +1,82 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// INTEGRATION MARIADB STRUCTS + +type MariaDBSecretEntry struct { + KeyName string `json:"keyName"` + Versions map[string]MariaDBSecretVersion `json:"secretVersions"` + CurrentVersion string `json:"defaultVersion"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +// Struct of keys stored inside the Vault +type MariaDBSecretVersion struct { + KeyVersion string `json:"keyVersion"` + EncryptedSecret string `json:"encryptedSecret"` + MessageAuthenticationCode *string `json:"messageAuthenticationCode"` + InitializationVector *string `json:"initializationVector"` + Version string `json:"version"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (s *MariaDBSecretEntry) InitSecret(keyName string, keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, creator Entity) { + s.CurrentVersion = "v1" + s.KeyName = keyName + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = "v1" + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = creator + secretVersion.Updated = creator + s.Created = creator + s.Updated = creator + s.Versions = make(map[string]MariaDBSecretVersion) + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) RotateSecret(keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, updater Entity) { + newSecretVersion := GetNewVersion(s.CurrentVersion) + s.CurrentVersion = newSecretVersion + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = newSecretVersion + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = updater + secretVersion.Updated = updater + s.Updated = updater + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) GetActiveVersion() MariaDBSecretVersion { + return s.Versions[s.CurrentVersion] +} +func (s *MariaDBSecretEntry) GetVersion(keyVersion string) MariaDBSecretVersion { + return s.Versions[keyVersion] +} + +// END INTEGRATION MARIADB STRUCTS diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9782f2d --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,316 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/integrationTests/client/client.go b/integrationTests/client/client.go new file mode 100644 index 0000000..70d4bee --- /dev/null +++ b/integrationTests/client/client.go @@ -0,0 +1,30 @@ +package integrationClient + +import ( + "fmt" + "log" + "os" + "time" + + "github.com/hashicorp/vault-client-go" +) + +func InitVaultClient() (*vault.Client){ + + // prepare a client with the given base address + client, err := vault.New( + vault.WithAddress(VaultConfig.Url+":"+fmt.Sprint(VaultConfig.Port)), + vault.WithRequestTimeout(30*time.Second), + ) + if err != nil { + log.Fatal(err) + os.Exit(1); + } + + // authenticate with a root token (insecure) + if err := client.SetToken(VaultConfig.RootToken); err != nil { + log.Fatal(err) + os.Exit(1); + } + return client; +} \ No newline at end of file diff --git a/integrationTests/client/client_config.go b/integrationTests/client/client_config.go new file mode 100644 index 0000000..148f2a9 --- /dev/null +++ b/integrationTests/client/client_config.go @@ -0,0 +1,15 @@ +package integrationClient + +type VaultClientConfig struct { + Port int + Url string + RootToken string + SecretsEnginePath string +} + +var VaultConfig VaultClientConfig=VaultClientConfig{ + Port: 8251, + Url: "http://127.0.0.1", + RootToken: "root", + SecretsEnginePath: "securosys-hsm", +} \ No newline at end of file diff --git a/integrationTests/client/go.mod b/integrationTests/client/go.mod new file mode 100644 index 0000000..02d12cd --- /dev/null +++ b/integrationTests/client/go.mod @@ -0,0 +1,24 @@ +module securosys.ch/integration/client + +go 1.21 + +toolchain go1.21.2 + +require github.com/hashicorp/vault-client-go v0.4.2 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stretchr/testify v1.8.2 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect +) diff --git a/integrationTests/client/go.sum b/integrationTests/client/go.sum new file mode 100644 index 0000000..3a52bd0 --- /dev/null +++ b/integrationTests/client/go.sum @@ -0,0 +1,58 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/vault-client-go v0.4.2 h1:XeUXb5jnDuCUhC8HRpkdGPLh1XtzXmiOnF0mXEbARxI= +github.com/hashicorp/vault-client-go v0.4.2/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integrationTests/docker/docker-compose.yml b/integrationTests/docker/docker-compose.yml new file mode 100644 index 0000000..1b00ff4 --- /dev/null +++ b/integrationTests/docker/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.0" +name: hashicorp-vault-test-containers +services: + hashicorp-vault-test: + image: hashicorp/vault:latest + container_name: "hashicorp-vault-test" + environment: + VAULT_DEV_ROOT_TOKEN_ID: root + VAULT_ADDR: 'https://0.0.0.0:8251' + VAULT_LOCAL_CONFIG: '{"listener": [{"tcp":{"address": "0.0.0.0:8251","tls_disable":"1"}}], "default_lease_ttl": "168h", "max_lease_ttl": "720h"}, "ui": true}' + volumes: + - ./plugins/:/vault/plugins + cap_add: + - IPC_LOCK + healthcheck: + retries: 5 + ports: + - "8251:8251" + privileged: true + command: server -dev -dev-root-token-id=root -dev-plugin-dir=/vault/plugins + networks: + - web + mariadb-test-integration: + build: + dockerfile: ./docker-files/MariaDB_Dockerfile + container_name: "mariadb-test-integration" + restart: always + environment: + MARIADB_ROOT_PASSWORD: example + volumes: + - ./mysql-config:/etc/mysql/conf.d + - ./db:/var/lib/mysql + networks: + - web + +networks: + web: + external: true + \ No newline at end of file diff --git a/integrationTests/docker/docker-files/MariaDB_Dockerfile b/integrationTests/docker/docker-files/MariaDB_Dockerfile new file mode 100644 index 0000000..7e5d37a --- /dev/null +++ b/integrationTests/docker/docker-files/MariaDB_Dockerfile @@ -0,0 +1,2 @@ +FROM mariadb:latest +RUN apt-get update && apt-get install -y mariadb-plugin-hashicorp-key-management diff --git a/integrationTests/docker/mysql-config/hashicorp.cnf b/integrationTests/docker/mysql-config/hashicorp.cnf new file mode 100644 index 0000000..d628bc7 --- /dev/null +++ b/integrationTests/docker/mysql-config/hashicorp.cnf @@ -0,0 +1,18 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="http://192.168.96.3:8251/v1/securosys-hsm/integrations/mariadb/test_async/?cipher_algorithm=RSA&key_name=rsa_with_policy&version=" +loose-hashicorp-key-management-token="root" +loose-hashicorp-key-management-check-kv-version="off" +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +loose-hashicorp-key-management-cache-timeout=31556952000 +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = OFF +innodb_encrypt_log = OFF +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 diff --git a/integrationTests/tests/a_enable_plugin_test.go b/integrationTests/tests/a_enable_plugin_test.go new file mode 100644 index 0000000..d16575a --- /dev/null +++ b/integrationTests/tests/a_enable_plugin_test.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "testing" + + "github.com/hashicorp/vault-client-go/schema" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestEnablePlugin(t *testing.T) { + + t.Run("A.1 Test Enable Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.System.MountsEnableSecretsEngine(ctx,integrationClient.VaultConfig.SecretsEnginePath,schema.MountsEnableSecretsEngineRequest{ + Type: "securosys-hsm", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/b_config_plugin_test.go b/integrationTests/tests/b_config_plugin_test.go new file mode 100644 index 0000000..d777766 --- /dev/null +++ b/integrationTests/tests/b_config_plugin_test.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfigPlugin(t *testing.T) { + + t.Run("B.1 Test Config Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/config",testHelpers.ConfigParams) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data["result"]==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s","null").Error()) + } + + if(!strings.Contains(resp.Data["result"].(string),"Connection successful:")){ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s",resp.Data["result"]).Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_aes_key_test.go b/integrationTests/tests/c_create_aes_key_test.go new file mode 100644 index 0000000..ccffd1b --- /dev/null +++ b/integrationTests/tests/c_create_aes_key_test.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateAESKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_aes"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_aes got %s","null").Error()) + } + }) + t.Run("C.3 Read AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["secretKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Key Secret got %s","null").Error()) + } + }) + t.Run("C.8 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_key_by_keyname_test.go b/integrationTests/tests/c_create_key_by_keyname_test.go new file mode 100644 index 0000000..285e47c --- /dev/null +++ b/integrationTests/tests/c_create_key_by_keyname_test.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateKeyByKeyNamePlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with label integrationTestKeyRSAName using name rsa-2048", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/type/rsa-2048/integration_test_key_rsa_name",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSAName", + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSAName"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSAName",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSAName_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test Remove Key RSA Key with name integrationTestKeyRSAName", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa_name",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_rsa_key_test.go b/integrationTests/tests/c_create_rsa_key_test.go new file mode 100644 index 0000000..90c1a10 --- /dev/null +++ b/integrationTests/tests/c_create_rsa_key_test.go @@ -0,0 +1,250 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["publicKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Public Key got %s","null").Error()) + } + if(resp.Data["privateKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Private Key got %s","null").Error()) + } + }) + t.Run("C.8 Update password RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/update-password",map[string]interface{}{ + "password":"", + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Test Remove Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_smart_rsa_key_test.go b/integrationTests/tests/c_create_smart_rsa_key_test.go new file mode 100644 index 0000000..dfdd792 --- /dev/null +++ b/integrationTests/tests/c_create_smart_rsa_key_test.go @@ -0,0 +1,255 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateSmartRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_smart_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_smart_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Block Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/block",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.8 UnBlock Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/unblock",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Update password Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/update-password",map[string]interface{}{ + "password":nil, + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/d_operations_on_key_test.go b/integrationTests/tests/d_operations_on_key_test.go new file mode 100644 index 0000000..8dc951b --- /dev/null +++ b/integrationTests/tests/d_operations_on_key_test.go @@ -0,0 +1,329 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestOperationsOnKeyPlugin(t *testing.T) { + + t.Run("D.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.2 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.3 Test Encrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.4 Test Encrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.5 Test Decrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.6 Test Decrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_key_aes",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.7 Test Sign using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + }) + t.Run("D.8 Test Verify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/verify/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "keyVersion":"v1", + "signatureAlgorithm":"SHA256_WITH_RSA", + "signature":resp.Data["signature"].(string), + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid got %s","null").Error()) + } + if(resp.Data["signatureValid"]==false){ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid %s got %s","true",resp.Data["signatureValid"]).Error()) + } + }) + t.Run("D.9 Test Modify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/modify",map[string]interface{}{ + "simplePolicy":`{"test":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnydX62tLYNF+Op1SRnX6avkkyQWlpYPagH85zxaGnMlZoMioqgjSOCuRvjaP7Y5noPMYayp3gJ2PwLXvw9+JlnL+iwklOcpONSa6gDoCDsk26DOoY0ELEPaGdW61mc2bj2hOQE0GEpPsRywJoRLS3B2e8bqRfAniAfGsUq3MK09iL5YOCuUCHCUiR9iZMSt0+Ek/kE4TrazbOCev1g6Ux2vOyTuQ6mF3wVuqwd8RhfvlNNKXbD2GD/jR3BwuhaodwzRPmDyDQPmEMwornxrMLavTcC+Igb4k5qol0Di6Oq8axpBvrH7KlxHT11Wd+ALKCsqoPSGxcIbd6TdN+ag9AQIDAQAB"}`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.11 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/go.mod b/integrationTests/tests/go.mod new file mode 100644 index 0000000..02bc999 --- /dev/null +++ b/integrationTests/tests/go.mod @@ -0,0 +1,6 @@ +module securosys.ch/integration/tests + +replace securosys.ch/integration/client => ./../client +replace securosys.ch/test-helpers => ./../../testHelpers + +go 1.19 diff --git a/integrationTests/tests/go.sum b/integrationTests/tests/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..0111058 --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.1.0 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..b55e030 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_API_URL", + "auth": "TOKEN", + "bearertoken": "TSB_BEARER_TOKEN", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/go.work b/tests/go.work new file mode 100644 index 0000000..7c33c4f --- /dev/null +++ b/tests/go.work @@ -0,0 +1,5 @@ +go 1.21 + +use ( + ./ +) \ No newline at end of file diff --git a/tests/go.work.sum b/tests/go.work.sum new file mode 100644 index 0000000..aff7933 --- /dev/null +++ b/tests/go.work.sum @@ -0,0 +1,163 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} diff --git a/tests/path_mariadb_integration_test.go b/tests/path_mariadb_integration_test.go new file mode 100644 index 0000000..b9b856e --- /dev/null +++ b/tests/path_mariadb_integration_test.go @@ -0,0 +1,111 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIntegrationMariaDB(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("A) add config", testEnv.AddConfig) + + t.Run("B) Test Creating RSA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + }) + t.Run("C)Add generate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("D)Read secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "integrations/mariadb/test/v1?key_name=custom_rsa_2048&cipher_algorithm=RSA", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("E) Rotate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("F) List secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "integrations/mariadb", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("G) Delete secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "integrations/mariadb/test", + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("H) Test Delete RSA key", func(t *testing.T) { + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + assert.NoError(t, err) + }) +} From d54fa67c8892671e898c8e114f9e8c99a8cf95cf Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Thu, 15 Feb 2024 13:05:52 +0100 Subject: [PATCH 14/16] Release v.1.1.0 --- .github/ISSUE_TEMPLATE/bug-report-sse.md | 49 + .github/ISSUE_TEMPLATE/feature-request-sse.md | 33 + .gitignore | 4 + LICENSE | 201 ++ Makefile | 201 ++ Readme.md | 1145 ++++++++++++ backend/backend.go | 140 ++ backend/go.mod | 62 + backend/go.sum | 223 +++ backend/path_config.go | 294 +++ backend/path_help.go | 452 +++++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 +++ backend/path_hsm_key_bls.go | 259 +++ backend/path_hsm_key_camellia.go | 225 +++ backend/path_hsm_key_chacha20.go | 208 +++ backend/path_hsm_key_dsa.go | 273 +++ backend/path_hsm_key_ec.go | 270 +++ backend/path_hsm_key_ed.go | 271 +++ backend/path_hsm_key_import.go | 306 ++++ backend/path_hsm_key_rsa.go | 273 +++ backend/path_hsm_key_tdea.go | 208 +++ backend/path_hsm_key_with_name.go | 295 +++ backend/path_hsm_keys.go | 1359 ++++++++++++++ backend/path_hsm_operations.go | 1631 +++++++++++++++++ backend/path_hsm_requests.go | 298 +++ backend/path_mariadb_integration.go | 666 +++++++ client/client.go | 48 + client/client_tsb.go | 1023 +++++++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + .../alpine3/docker-compose-alpine3.yml | 56 + docker-builder/build-in-docker.sh | 12 + etc/example/mariaDb.cfg | 22 + etc/example/policy.json | 93 + etc/release_notes/Release_Notes.md | 29 + go.mod | 80 + go.sum | 254 +++ go.work | 8 + go.work.sum | 164 ++ helpers/consts.go | 53 + helpers/functions.go | 234 +++ helpers/go.mod | 57 + helpers/go.sum | 223 +++ helpers/mariadb_structs.go | 82 + helpers/structs.go | 316 ++++ integrationTests/client/client.go | 30 + integrationTests/client/client_config.go | 15 + integrationTests/client/go.mod | 24 + integrationTests/client/go.sum | 58 + integrationTests/docker/docker-compose.yml | 39 + .../docker/docker-files/MariaDB_Dockerfile | 2 + .../docker/mysql-config/hashicorp.cnf | 18 + .../tests/a_enable_plugin_test.go | 48 + .../tests/b_config_plugin_test.go | 55 + .../tests/c_create_aes_key_test.go | 234 +++ .../tests/c_create_key_by_keyname_test.go | 93 + .../tests/c_create_rsa_key_test.go | 250 +++ .../tests/c_create_smart_rsa_key_test.go | 255 +++ .../tests/d_operations_on_key_test.go | 329 ++++ integrationTests/tests/go.mod | 6 + integrationTests/tests/go.sum | 0 project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 +++ testHelpers/test_client_tsb.go | 151 ++ testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 ++++++++ tests/go.mod | 66 + tests/go.sum | 223 +++ tests/go.work | 5 + tests/go.work.sum | 163 ++ tests/path_config_test.go | 153 ++ tests/path_hsm_key_aes_test.go | 133 ++ tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 ++ tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 ++ tests/path_hsm_key_tdea_test.go | 136 ++ tests/path_hsm_key_using_type_name_test.go | 245 +++ tests/path_hsm_keys_rotation_test.go | 836 +++++++++ tests/path_hsm_keys_test.go | 312 ++++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++++ tests/path_hsm_operations_sign_test.go | 647 +++++++ tests/path_hsm_operations_unwrap_test.go | 675 +++++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++++++++ tests/path_hsm_operations_wrap_test.go | 242 +++ tests/path_hsm_requests_test.go | 299 +++ tests/path_mariadb_integration_test.go | 111 ++ 95 files changed, 23286 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-sse.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-sse.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 backend/path_mariadb_integration.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 docker-builder/alpine3/docker-compose-alpine3.yml create mode 100644 docker-builder/build-in-docker.sh create mode 100644 etc/example/mariaDb.cfg create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 go.work create mode 100644 go.work.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/mariadb_structs.go create mode 100644 helpers/structs.go create mode 100644 integrationTests/client/client.go create mode 100644 integrationTests/client/client_config.go create mode 100644 integrationTests/client/go.mod create mode 100644 integrationTests/client/go.sum create mode 100644 integrationTests/docker/docker-compose.yml create mode 100644 integrationTests/docker/docker-files/MariaDB_Dockerfile create mode 100644 integrationTests/docker/mysql-config/hashicorp.cnf create mode 100644 integrationTests/tests/a_enable_plugin_test.go create mode 100644 integrationTests/tests/b_config_plugin_test.go create mode 100644 integrationTests/tests/c_create_aes_key_test.go create mode 100644 integrationTests/tests/c_create_key_by_keyname_test.go create mode 100644 integrationTests/tests/c_create_rsa_key_test.go create mode 100644 integrationTests/tests/c_create_smart_rsa_key_test.go create mode 100644 integrationTests/tests/d_operations_on_key_test.go create mode 100644 integrationTests/tests/go.mod create mode 100644 integrationTests/tests/go.sum create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/go.work create mode 100644 tests/go.work.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go create mode 100644 tests/path_mariadb_integration_test.go diff --git a/.github/ISSUE_TEMPLATE/bug-report-sse.md b/.github/ISSUE_TEMPLATE/bug-report-sse.md new file mode 100644 index 0000000..40777e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-sse.md @@ -0,0 +1,49 @@ +--- +name: Bug report SSE +about: Create a report to help us improve +title: "[BUG] " +labels: '' +assignees: Peter-FNet + +--- + + + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment:** +* Vault Server Version (retrieve with `vault status`): +* Vault CLI Version (retrieve with `vault version`): +* Server Operating System/Architecture: + +Vault server configuration file(s): + +```hcl +# Paste your Vault config here. +# Be sure to scrub any sensitive values +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request-sse.md b/.github/ISSUE_TEMPLATE/feature-request-sse.md new file mode 100644 index 0000000..8264e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-sse.md @@ -0,0 +1,33 @@ +--- +name: Feature request SSE +about: Suggest an idea for this project +title: "[FEAT]" +labels: '' +assignees: Peter-FNet + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Explain any additional use-cases** +If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5375b60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +builds +vault +deploy +.gitlab-ci.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a142d1d --- /dev/null +++ b/Makefile @@ -0,0 +1,201 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` + +ifndef ARTIFACT_NAME +override ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +endif + +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + make release-alpine3 + echo "Finished!"; + +release-alpine3: + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-amd64 + make clean-docker-builder IMAGE=amd64/golang + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-i386 + make clean-docker-builder IMAGE=i386/golang + +clean-docker-builder: + @if [ "$$(docker images | grep '$(IMAGE)')" != "" ]; then \ + docker rmi -f $$(docker images | grep '$(IMAGE)' | awk '{ print $$3}') 2> /dev/null || true ; \ + fi; + docker volume prune -f + docker container prune -f + docker network prune -f + +run-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml up --build -d +clean-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml down --remove-orphans --rmi all + docker volume prune -f + docker container prune -f +integration-tests: + rm -fr integrationTests/docker/plugins/securosys-hsm + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -o integrationTests/docker/plugins/securosys-hsm cmd/securosys-hsm/main.go + make run-docker-test-container + + sleep 5 + go install github.com/jstemmer/go-junit-report/v2@latest + cd integrationTests/tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}integration_junit_report.xml -set-exit-code + + + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 15m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4828e0e --- /dev/null +++ b/Readme.md @@ -0,0 +1,1145 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Integrations](#integrations) + - [MariaDB](#mariadb) + - [Example usage](#mariadb-usage-example) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate and `keypath` with local PATH to the key. +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for Certificate authorization**: +```shell +$ vault write securosys-hsm/config +auth="CERT" +certpath="local_absolute_path_to_certificate.pem" +keypath="local_absolute_path_to_private.key" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=CERT' \ +--data-urlencode 'certpath=local_absolute_path_to_certificate.pem' \ +--data-urlencode 'keypath=local_absolute_path_to_private.pem' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Integrations +### MariaDB +Encryption on MariaDB can be enabled using existing plugin [Hashicorp Key Management Plugin](https://mariadb.com/kb/en/hashicorp-key-management-plugin/) +This integration stores generated secret in Secrets engine, encrypted by provided key. +**Supported Key Types**/**Algorithm** combinations: +| Key Type | Algorithm | +|----------|:-------------:| +| **RSA** |RSA_PADDING_OAEP_WITH_SHA512
RSA
RSA_PADDING_OAEP_WITH_SHA224
RSA_PADDING_OAEP_WITH_SHA256
RSA_PADDING_OAEP_WITH_SHA1
RSA_PADDING_OAEP
RSA_PADDING_OAEP_WITH_SHA384
RSA_NO_PADDING| +|**AES**|AES_GCM
AES_CTR
AES_ECB
AES_CBC_NO_PADDING
AES | +| **CHACHA20** | CHACHA20
CHACHA20_AEAD| +| **CAMELLIA** | CAMELLIA
CAMELLIA_CBC_NO_PADDING
CAMELLIA_ECB | +|**TDEA**| TDEA_CBC
TDEA_ECB
TDEA_CBC_NO_PADDING | + +>**Note** - Plugin supports **asynchronous decrypt operation** using key type **RSA** with **policy** with setup **ruleUse**. Using the key with policy will **stop** the decrypt operation and **wait for approvals** to be collected. + +There are a **serval steps** that is needed to be done before setup encryption on MariaDB +1) [Create / Register key](#manage-keys) into **Secrets Engine** +1) Generate new **secret** and encrypt it using stored key + ```shell + $ vault write securosys-hsm/integrations/mariadb/{secret-name} + keyName={key-name-from-secret-engine} + cipherAlgorithm={cipher-algorithm} + [additionalAuthenticationData={additional-authentication-data}] + [tagLength={tag-length}] + [password={password-for-a-key}] + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/integrations/mariadb/{secret-name} ' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName={key-name-from-secret-engine}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + >**Note** - Every request on this endpoint using same **key name** and **secret name** will **rotate secret** +1) The last step is add this configuration to **my.cfg** + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" + loose-hashicorp-key-management-token="{vault_access_token}" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + >**Note** - In **loose-hashicorp-key-management-vault-url** url need to ends with **&version=**. Plugin from **MariaDB** automatically add to end of url **number of secret version** +#### MariaDB usage example +This example using default configuration for **Hashicorp Vault dev server**. +| Data | Value | +|----------|:-------------:| +| **vault address** | https://localhost:8200 | +| **vault access token** | root | +1) **Create key** *MariaDBEncryptionKey* with key size *4096* with attributes at last "decrypt" equals *true* on HSM and store it as *mariadb_encryption_key* on **Secrets engine** + ```shell + $ vault write securosys-hsm/keys/rsa/mariadb_encryption_key + keyLabel="MariaDBEncryptionKey" + keySize=4096 + attributes='{"decrypt": true,"sign": false,"unwrap": false,"derive": true,"sensitive": true,"extractable": false,"modifiable": false,"copyable": false,"destroyable": true}' + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/keys/rsa/mariadb_encryption_key' \ + --header 'X-Vault-Token: root' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel=MariaDBEncryptionKey' \ + --data-urlencode 'keySize=4096' \ + --data-urlencode 'attributes={ + "decrypt": true, + "sign": false, + "unwrap": false, + "derive": true, + "sensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": false, + "copyable": false, + "destroyable": true + }' + ``` +1) Generate new **secret** called *mariadb_secret* and **encrypt it** using cipher algorithm *RSA* and stored key *mariadb_encryption_key* in **Secrets engine** + ```shell + $ vault write securosys-hsm/integrations/mariadb/mariadb_secret + keyName=mariadb_encryption_key + cipherAlgorithm=RSA + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret ' \ + --header 'X-Vault-Token: root' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName=mariadb_encryption_key' \ + --data-urlencode 'cipherAlgorithm=RSA' + ``` +3. Configure **MariaDB plugin** "Hashicorp Key Management" in database configuration in **my.cnf** + + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret/?key_name=mariadb_encryption_key&cipher_algorithm=RSA&version=" + loose-hashicorp-key-management-token="root" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + + + +--- +## Appendix +### Frequently Asked Questions +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..67cf38a --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,140 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + pathMariaDBIntegration(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..29a1fac --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,294 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "keypath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to key", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "KeyPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if keypath, ok := data.GetOk("keypath"); ok { + config.KeyPath = keypath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing keypath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.KeyPath) + + if err != nil { + return nil, fmt.Errorf("Keypath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..8281fe0 --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,452 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..32954d9 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string), map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy, map[string]string{}) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil, map[string]string{}) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString, nil) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..e24fe58 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} diff --git a/backend/path_mariadb_integration.go b/backend/path_mariadb_integration.go new file mode 100644 index 0000000..0101c1d --- /dev/null +++ b/backend/path_mariadb_integration.go @@ -0,0 +1,666 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for create Camellia Keys +func pathMariaDBIntegration(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "keyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsDelete, + }, + }, + HelpSynopsis: pathIntegrationMariaDBWriteHelpSynopsis, + HelpDescription: pathIntegrationMariaDBWriteHelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("version") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV1HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV1HelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV2HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV2HelpDescription, + }, + { + Pattern: "integrations/mariadb/?$", + Fields: map[string]*framework.FieldSchema{}, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsList, + }, + }, + HelpSynopsis: pathIntegrationMariaDBListHelpSynopsis, + HelpDescription: pathIntegrationMariaDBListHelpDescription, + }, + } +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "intergration/mariadb/") + if err != nil { + return nil, err + } + secrets := make([]string, 0, len(entries)) + secretsInfo := make(map[string]interface{}) + for _, name := range entries { + secrets = append(secrets, name) + secret, err := b.GetMariaDBSecret(ctx, req.Storage, name) + if err == nil { + secretsInfo[name] = map[string]interface{}{ + "KeyName": secret.KeyName, + "Version": secret.CurrentVersion, + "Created": secret.Created.Name, + "Updated": secret.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(secrets, secretsInfo), nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, errGet := b.GetMariaDBSecret(ctx, req.Storage, name) + if errGet != nil { + return nil, fmt.Errorf("error deleting mariadb secret: %w", errGet) + } + if storedSecret == nil { + return nil, fmt.Errorf("error deleting mariadb secret: secret with name %s not exists", d.Get("name").(string)) + + } + + err := req.Storage.Delete(ctx, "intergration/mariadb/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + rotate := false + if storedSecret != nil { + rotate = true + // return nil, fmt.Errorf("error secret with name: %s exists", name) + } else { + storedSecret = &helpers.MariaDBSecretEntry{} + + } + + keyName := d.Get("keyName").(string) + + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload := b64.StdEncoding.EncodeToString([]byte(helpers.GeneratePassword(32, false, false, false, true))) + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + sysView := b.System() + creator := helpers.Entity{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + creator.Aliases = entity.Aliases + creator.Id = entity.ID + creator.Name = entity.Name + creator.Date = time.Now().UTC() + + } else { + creator.Aliases = nil + creator.Id = "root" + creator.Name = "root" + creator.Date = time.Now().UTC() + + } + var messageAuthenticationCode *string = nil + if result["messageAuthenticationCode"] != nil { + temp := result["messageAuthenticationCode"].(string) + messageAuthenticationCode = &temp + } + var initializationVector *string = nil + if result["initializationVector"] != nil { + temp := result["initializationVector"].(string) + initializationVector = &temp + } + if !rotate { + storedSecret.InitSecret(keyName, keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + } else { + storedSecret.RotateSecret(keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + + } + if err := SetMariaDBSecret(ctx, req.Storage, name, storedSecret); err != nil { + return nil, err + } + + response := map[string]interface{}{} + now := storedSecret.GetActiveVersion().Created.Date + version := storedSecret.GetActiveVersion().Version + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + query := d.Get("query").(string) + if strings.HasPrefix(query, "?") { + query = query[1:] + } + params, err := url.ParseQuery(query) + + if query == "" { + str := "" + for key, value := range req.Data { + str = str + key + "=" + value.(string) + "&" + } + str = str[:len(str)-1] + params, err = url.ParseQuery(str) + } + + if err != nil { + return nil, err + } + name := d.Get("name").(string) + + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + if storedSecret == nil { + return nil, fmt.Errorf("error secret with name: %s not exists", name) + } + + version := "1" + if params.Has("version") { + if !strings.Contains(params.Get("version"), "?version=") { + version = storedSecret.CurrentVersion + } else { + parts := strings.Split(params.Get("version"), "?version=") + version = "v" + parts[1] + } + } else { + ver, ok := d.GetOk("version") + if !ok { + return nil, fmt.Errorf("error: missing version") + } + version = ver.(string) + } + + if !params.Has("key_name") { + return nil, fmt.Errorf("key_name query param not exists") + } + keyEntry, err := b.GetKey(ctx, req.Storage, params.Get("key_name")) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + keyName := params.Get("key_name") + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + + if !helpers.ContainsKey(storedSecret.Versions, version) { + return nil, fmt.Errorf("Secret version %s is not exists.", version) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload := storedSecret.GetVersion(version).EncryptedSecret + + if !params.Has("cipher_algorithm") { + return nil, fmt.Errorf("cipher_algorithm query param not exists") + } + + cipherAlgorithm := params.Get("cipher_algorithm") + if keyEntry.KeyTypeName != "aes256-gcm96" && cipherAlgorithm == "" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVectorString := "" + if params.Has("initialization_vector") { + initializationVectorString = params.Get("initialization_vector") + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + passwordString := "" + if params.Has("password") { + passwordString = params.Get("password") + } + tagLengthInt := -1 + if params.Has("tag_length") { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + } + if keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationDataString := "" + if params.Has("aad") { + additionalAuthenticationDataString = params.Get("aad") + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationDataString) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData (param aad) is not valid base64 string") + } + } + client, err := b.GetClient(ctx, req.Storage) + async := false + decrypted := "" + if len(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + async = true + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString, map[string]string{"integration": "MariaDB Encrypt"}) + if errEnc != nil { + return nil, errEnc + } + var resp *helpers.RequestResponse + resp, _, _ = client.GetRequest(requestId) + for resp.Status == "PENDING" { + time.Sleep(1000) + resp, _, _ = client.GetRequest(requestId) + } + if resp.Status != "EXECUTED" { + return nil, fmt.Errorf("error on async decrypt. Expected Status '%s' got '%s'", "EXECUTED", resp.Status) + } + decrypted = resp.Result + + } + } + } + if !async { + resultSync, errEnc := client.Decrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + decrypted = resultSync["payload"].(string) + } + + if cipherAlgorithm == "AES_ECB" || + cipherAlgorithm == "AES_CBC_NO_PADDING" || + cipherAlgorithm == "CAMELLIA_ECB" || + cipherAlgorithm == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + decoded, _ := base64.StdEncoding.DecodeString(decrypted) + response := map[string]interface{}{} + response["data"] = map[string]interface{}{"data": string(decoded)} + now := storedSecret.GetVersion(version).Created.Date + + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} + +// This function helps with saving key in Secrets Engine +func SetMariaDBSecret(ctx context.Context, s logical.Storage, name string, secretEntry *helpers.MariaDBSecretEntry) error { + entry, err := logical.StorageEntryJSON("intergration/mariadb/"+name, secretEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage secret") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetMariaDBSecret(ctx context.Context, s logical.Storage, name string) (*helpers.MariaDBSecretEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "intergration/mariadb/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var secret helpers.MariaDBSecretEntry + + if err := entry.DecodeJSON(&secret); err != nil { + return nil, err + } + return &secret, nil +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..b50c7e2 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1023 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + KeyPath: data["keypath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + ` + passwordString + ` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy, customMetaData map[string]string) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo, customMetaData) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString := "" + if len(keyToBeWrappedPasswordJson) > 2 { + keyToBeWrappedPasswordString = `"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString := "" + if len(wrapKeyPasswordJson) > 2 { + wrapKeyPasswordString = `"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + ` + keyToBeWrappedPasswordString + ` + "wrapKeyName": "` + wrapKeyName + `", + ` + wrapKeyPasswordString + ` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + ` + passwordString + ` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + ` + passwordString + ` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + ` + passwordString + ` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + ` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString := "" + if len(charsNewPasswordJson) > 2 { + newPasswordString = `"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + newPasswordString + ` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + passwordString + ` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + clientTLSCert, err := tls.LoadX509KeyPair(c.Auth.CertPath, c.Auth.KeyPath) + if err != nil { + log.Fatalf("Error loading certificate and key file: %v", err) + return nil, err, 0 + } + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + InsecureSkipVerify: true, + Certificates: []tls.Certificate{clientTLSCert}, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/docker-builder/alpine3/docker-compose-alpine3.yml b/docker-builder/alpine3/docker-compose-alpine3.yml new file mode 100644 index 0000000..1190d88 --- /dev/null +++ b/docker-builder/alpine3/docker-compose-alpine3.yml @@ -0,0 +1,56 @@ + version: "3.3" + services: + golang-builder-alpine3-amd64: + platform: linux/amd64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=amd64 + image: amd64/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-amd64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-i386: + platform: linux/i386 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=386 + image: i386/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-i386 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-arm64: + platform: linux/arm64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=arm64 + image: arm64v8/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-arm64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" \ No newline at end of file diff --git a/docker-builder/build-in-docker.sh b/docker-builder/build-in-docker.sh new file mode 100644 index 0000000..adc15b2 --- /dev/null +++ b/docker-builder/build-in-docker.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd .. +echo "Build ${ARTIFACT_NAME} in ${DOCKER_OS}_${DOCKER_ARCH}"; + cd /src + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; + cd builds; + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; + zip -9 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; + shasum -a 256 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; + cd ..; + rm builds/securosys-hsm; + rm builds/securosys-hsm_SHA256SUM; \ No newline at end of file diff --git a/etc/example/mariaDb.cfg b/etc/example/mariaDb.cfg new file mode 100644 index 0000000..298e73a --- /dev/null +++ b/etc/example/mariaDb.cfg @@ -0,0 +1,22 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" +loose-hashicorp-key-management-token="{vault_access_token}" +loose-hashicorp-key-management-check-kv-version="off" +#max timeout is 86400 seconds +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +#1 year in miliseconds +loose-hashicorp-key-management-cache-timeout=31556952000 +#1 year in miliseconds +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +#Example of innodb config +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = ON +innodb_encrypt_log = ON +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 \ No newline at end of file diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..8e00e02 --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,93 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..6eebb05 --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,29 @@ +# Securosys Hashicorp Vault Secrets Engine 1.1.0 +Issued: Dec, 6, 2023 +## Documentation Change +- Update Readme.md - added information about supporting and how to configure encryption on MariaDB +## Feature +- Added integration with MariaDB encryption +## Bugfix +- Fixed authentication with TSB using mTLS + +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build/ + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2d78c0c --- /dev/null +++ b/go.mod @@ -0,0 +1,80 @@ +module secretengine + +go 1.21 + +toolchain go1.21.2 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers + +replace securosys.ch/tests => ./tests + +replace securosys.ch/integration/client => ./integrationTests/client + +replace securosys.ch/integration/tests => ./integrationTests/tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/frankban/quicktest v1.14.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afae25d --- /dev/null +++ b/go.sum @@ -0,0 +1,254 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work new file mode 100644 index 0000000..ad36518 --- /dev/null +++ b/go.work @@ -0,0 +1,8 @@ +go 1.21 + +use ( + ./ + ./backend + ./integrationTests/client + ./integrationTests/tests +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..976ca94 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,164 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..bdc47e4 --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "math/rand" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} +func GetVersionNumber(version string) int { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + return versionInt +} +func GetVersionString(version string) string { + return strings.Replace(version, "v", "", 1) +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string, customMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + for key, value := range customMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + specialBytes = "!@#$%^&*()_+-=[]{}\\|;':\",.<>/?`~" + numBytes = "0123456789" + hexDecimalBytes = "0123456789ABCDEF" +) + +func GeneratePassword(length int, useLetters bool, useSpecial bool, useNum bool, useHexadecimal bool) string { + rand.Seed(time.Now().UnixNano()) + b := make([]byte, length) + arrayForRandom := make([]byte, 0) + if useLetters { + arrayForRandom = append(arrayForRandom, letterBytes...) + } + if useSpecial { + arrayForRandom = append(arrayForRandom, specialBytes...) + } + if useNum { + arrayForRandom = append(arrayForRandom, numBytes...) + } + if useHexadecimal { + arrayForRandom = append(arrayForRandom, hexDecimalBytes...) + + } + + for i := range b { + b[i] = arrayForRandom[rand.Intn(len(arrayForRandom))] + } + return string(b) +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/mariadb_structs.go b/helpers/mariadb_structs.go new file mode 100644 index 0000000..97210ac --- /dev/null +++ b/helpers/mariadb_structs.go @@ -0,0 +1,82 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// INTEGRATION MARIADB STRUCTS + +type MariaDBSecretEntry struct { + KeyName string `json:"keyName"` + Versions map[string]MariaDBSecretVersion `json:"secretVersions"` + CurrentVersion string `json:"defaultVersion"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +// Struct of keys stored inside the Vault +type MariaDBSecretVersion struct { + KeyVersion string `json:"keyVersion"` + EncryptedSecret string `json:"encryptedSecret"` + MessageAuthenticationCode *string `json:"messageAuthenticationCode"` + InitializationVector *string `json:"initializationVector"` + Version string `json:"version"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (s *MariaDBSecretEntry) InitSecret(keyName string, keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, creator Entity) { + s.CurrentVersion = "v1" + s.KeyName = keyName + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = "v1" + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = creator + secretVersion.Updated = creator + s.Created = creator + s.Updated = creator + s.Versions = make(map[string]MariaDBSecretVersion) + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) RotateSecret(keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, updater Entity) { + newSecretVersion := GetNewVersion(s.CurrentVersion) + s.CurrentVersion = newSecretVersion + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = newSecretVersion + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = updater + secretVersion.Updated = updater + s.Updated = updater + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) GetActiveVersion() MariaDBSecretVersion { + return s.Versions[s.CurrentVersion] +} +func (s *MariaDBSecretEntry) GetVersion(keyVersion string) MariaDBSecretVersion { + return s.Versions[keyVersion] +} + +// END INTEGRATION MARIADB STRUCTS diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9782f2d --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,316 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/integrationTests/client/client.go b/integrationTests/client/client.go new file mode 100644 index 0000000..70d4bee --- /dev/null +++ b/integrationTests/client/client.go @@ -0,0 +1,30 @@ +package integrationClient + +import ( + "fmt" + "log" + "os" + "time" + + "github.com/hashicorp/vault-client-go" +) + +func InitVaultClient() (*vault.Client){ + + // prepare a client with the given base address + client, err := vault.New( + vault.WithAddress(VaultConfig.Url+":"+fmt.Sprint(VaultConfig.Port)), + vault.WithRequestTimeout(30*time.Second), + ) + if err != nil { + log.Fatal(err) + os.Exit(1); + } + + // authenticate with a root token (insecure) + if err := client.SetToken(VaultConfig.RootToken); err != nil { + log.Fatal(err) + os.Exit(1); + } + return client; +} \ No newline at end of file diff --git a/integrationTests/client/client_config.go b/integrationTests/client/client_config.go new file mode 100644 index 0000000..148f2a9 --- /dev/null +++ b/integrationTests/client/client_config.go @@ -0,0 +1,15 @@ +package integrationClient + +type VaultClientConfig struct { + Port int + Url string + RootToken string + SecretsEnginePath string +} + +var VaultConfig VaultClientConfig=VaultClientConfig{ + Port: 8251, + Url: "http://127.0.0.1", + RootToken: "root", + SecretsEnginePath: "securosys-hsm", +} \ No newline at end of file diff --git a/integrationTests/client/go.mod b/integrationTests/client/go.mod new file mode 100644 index 0000000..02d12cd --- /dev/null +++ b/integrationTests/client/go.mod @@ -0,0 +1,24 @@ +module securosys.ch/integration/client + +go 1.21 + +toolchain go1.21.2 + +require github.com/hashicorp/vault-client-go v0.4.2 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stretchr/testify v1.8.2 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect +) diff --git a/integrationTests/client/go.sum b/integrationTests/client/go.sum new file mode 100644 index 0000000..3a52bd0 --- /dev/null +++ b/integrationTests/client/go.sum @@ -0,0 +1,58 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/vault-client-go v0.4.2 h1:XeUXb5jnDuCUhC8HRpkdGPLh1XtzXmiOnF0mXEbARxI= +github.com/hashicorp/vault-client-go v0.4.2/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integrationTests/docker/docker-compose.yml b/integrationTests/docker/docker-compose.yml new file mode 100644 index 0000000..1b00ff4 --- /dev/null +++ b/integrationTests/docker/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.0" +name: hashicorp-vault-test-containers +services: + hashicorp-vault-test: + image: hashicorp/vault:latest + container_name: "hashicorp-vault-test" + environment: + VAULT_DEV_ROOT_TOKEN_ID: root + VAULT_ADDR: 'https://0.0.0.0:8251' + VAULT_LOCAL_CONFIG: '{"listener": [{"tcp":{"address": "0.0.0.0:8251","tls_disable":"1"}}], "default_lease_ttl": "168h", "max_lease_ttl": "720h"}, "ui": true}' + volumes: + - ./plugins/:/vault/plugins + cap_add: + - IPC_LOCK + healthcheck: + retries: 5 + ports: + - "8251:8251" + privileged: true + command: server -dev -dev-root-token-id=root -dev-plugin-dir=/vault/plugins + networks: + - web + mariadb-test-integration: + build: + dockerfile: ./docker-files/MariaDB_Dockerfile + container_name: "mariadb-test-integration" + restart: always + environment: + MARIADB_ROOT_PASSWORD: example + volumes: + - ./mysql-config:/etc/mysql/conf.d + - ./db:/var/lib/mysql + networks: + - web + +networks: + web: + external: true + \ No newline at end of file diff --git a/integrationTests/docker/docker-files/MariaDB_Dockerfile b/integrationTests/docker/docker-files/MariaDB_Dockerfile new file mode 100644 index 0000000..7e5d37a --- /dev/null +++ b/integrationTests/docker/docker-files/MariaDB_Dockerfile @@ -0,0 +1,2 @@ +FROM mariadb:latest +RUN apt-get update && apt-get install -y mariadb-plugin-hashicorp-key-management diff --git a/integrationTests/docker/mysql-config/hashicorp.cnf b/integrationTests/docker/mysql-config/hashicorp.cnf new file mode 100644 index 0000000..d628bc7 --- /dev/null +++ b/integrationTests/docker/mysql-config/hashicorp.cnf @@ -0,0 +1,18 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="http://192.168.96.3:8251/v1/securosys-hsm/integrations/mariadb/test_async/?cipher_algorithm=RSA&key_name=rsa_with_policy&version=" +loose-hashicorp-key-management-token="root" +loose-hashicorp-key-management-check-kv-version="off" +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +loose-hashicorp-key-management-cache-timeout=31556952000 +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = OFF +innodb_encrypt_log = OFF +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 diff --git a/integrationTests/tests/a_enable_plugin_test.go b/integrationTests/tests/a_enable_plugin_test.go new file mode 100644 index 0000000..d16575a --- /dev/null +++ b/integrationTests/tests/a_enable_plugin_test.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "testing" + + "github.com/hashicorp/vault-client-go/schema" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestEnablePlugin(t *testing.T) { + + t.Run("A.1 Test Enable Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.System.MountsEnableSecretsEngine(ctx,integrationClient.VaultConfig.SecretsEnginePath,schema.MountsEnableSecretsEngineRequest{ + Type: "securosys-hsm", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/b_config_plugin_test.go b/integrationTests/tests/b_config_plugin_test.go new file mode 100644 index 0000000..d777766 --- /dev/null +++ b/integrationTests/tests/b_config_plugin_test.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfigPlugin(t *testing.T) { + + t.Run("B.1 Test Config Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/config",testHelpers.ConfigParams) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data["result"]==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s","null").Error()) + } + + if(!strings.Contains(resp.Data["result"].(string),"Connection successful:")){ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s",resp.Data["result"]).Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_aes_key_test.go b/integrationTests/tests/c_create_aes_key_test.go new file mode 100644 index 0000000..ccffd1b --- /dev/null +++ b/integrationTests/tests/c_create_aes_key_test.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateAESKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_aes"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_aes got %s","null").Error()) + } + }) + t.Run("C.3 Read AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["secretKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Key Secret got %s","null").Error()) + } + }) + t.Run("C.8 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_key_by_keyname_test.go b/integrationTests/tests/c_create_key_by_keyname_test.go new file mode 100644 index 0000000..285e47c --- /dev/null +++ b/integrationTests/tests/c_create_key_by_keyname_test.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateKeyByKeyNamePlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with label integrationTestKeyRSAName using name rsa-2048", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/type/rsa-2048/integration_test_key_rsa_name",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSAName", + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSAName"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSAName",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSAName_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test Remove Key RSA Key with name integrationTestKeyRSAName", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa_name",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_rsa_key_test.go b/integrationTests/tests/c_create_rsa_key_test.go new file mode 100644 index 0000000..90c1a10 --- /dev/null +++ b/integrationTests/tests/c_create_rsa_key_test.go @@ -0,0 +1,250 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["publicKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Public Key got %s","null").Error()) + } + if(resp.Data["privateKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Private Key got %s","null").Error()) + } + }) + t.Run("C.8 Update password RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/update-password",map[string]interface{}{ + "password":"", + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Test Remove Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_smart_rsa_key_test.go b/integrationTests/tests/c_create_smart_rsa_key_test.go new file mode 100644 index 0000000..dfdd792 --- /dev/null +++ b/integrationTests/tests/c_create_smart_rsa_key_test.go @@ -0,0 +1,255 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateSmartRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_smart_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_smart_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Block Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/block",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.8 UnBlock Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/unblock",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Update password Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/update-password",map[string]interface{}{ + "password":nil, + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/d_operations_on_key_test.go b/integrationTests/tests/d_operations_on_key_test.go new file mode 100644 index 0000000..8dc951b --- /dev/null +++ b/integrationTests/tests/d_operations_on_key_test.go @@ -0,0 +1,329 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestOperationsOnKeyPlugin(t *testing.T) { + + t.Run("D.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.2 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.3 Test Encrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.4 Test Encrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.5 Test Decrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.6 Test Decrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_key_aes",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.7 Test Sign using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + }) + t.Run("D.8 Test Verify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/verify/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "keyVersion":"v1", + "signatureAlgorithm":"SHA256_WITH_RSA", + "signature":resp.Data["signature"].(string), + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid got %s","null").Error()) + } + if(resp.Data["signatureValid"]==false){ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid %s got %s","true",resp.Data["signatureValid"]).Error()) + } + }) + t.Run("D.9 Test Modify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/modify",map[string]interface{}{ + "simplePolicy":`{"test":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnydX62tLYNF+Op1SRnX6avkkyQWlpYPagH85zxaGnMlZoMioqgjSOCuRvjaP7Y5noPMYayp3gJ2PwLXvw9+JlnL+iwklOcpONSa6gDoCDsk26DOoY0ELEPaGdW61mc2bj2hOQE0GEpPsRywJoRLS3B2e8bqRfAniAfGsUq3MK09iL5YOCuUCHCUiR9iZMSt0+Ek/kE4TrazbOCev1g6Ux2vOyTuQ6mF3wVuqwd8RhfvlNNKXbD2GD/jR3BwuhaodwzRPmDyDQPmEMwornxrMLavTcC+Igb4k5qol0Di6Oq8axpBvrH7KlxHT11Wd+ALKCsqoPSGxcIbd6TdN+ag9AQIDAQAB"}`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.11 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/go.mod b/integrationTests/tests/go.mod new file mode 100644 index 0000000..02bc999 --- /dev/null +++ b/integrationTests/tests/go.mod @@ -0,0 +1,6 @@ +module securosys.ch/integration/tests + +replace securosys.ch/integration/client => ./../client +replace securosys.ch/test-helpers => ./../../testHelpers + +go 1.19 diff --git a/integrationTests/tests/go.sum b/integrationTests/tests/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..0111058 --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.1.0 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..b55e030 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_API_URL", + "auth": "TOKEN", + "bearertoken": "TSB_BEARER_TOKEN", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/go.work b/tests/go.work new file mode 100644 index 0000000..7c33c4f --- /dev/null +++ b/tests/go.work @@ -0,0 +1,5 @@ +go 1.21 + +use ( + ./ +) \ No newline at end of file diff --git a/tests/go.work.sum b/tests/go.work.sum new file mode 100644 index 0000000..aff7933 --- /dev/null +++ b/tests/go.work.sum @@ -0,0 +1,163 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} diff --git a/tests/path_mariadb_integration_test.go b/tests/path_mariadb_integration_test.go new file mode 100644 index 0000000..b9b856e --- /dev/null +++ b/tests/path_mariadb_integration_test.go @@ -0,0 +1,111 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIntegrationMariaDB(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("A) add config", testEnv.AddConfig) + + t.Run("B) Test Creating RSA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + }) + t.Run("C)Add generate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("D)Read secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "integrations/mariadb/test/v1?key_name=custom_rsa_2048&cipher_algorithm=RSA", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("E) Rotate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("F) List secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "integrations/mariadb", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("G) Delete secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "integrations/mariadb/test", + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("H) Test Delete RSA key", func(t *testing.T) { + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + assert.NoError(t, err) + }) +} From b6b38f4caca5f17c270c367e6bfac4a7e0f848d6 Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Mon, 8 Apr 2024 09:44:54 +0200 Subject: [PATCH 15/16] Release v.1.1.0 --- .github/ISSUE_TEMPLATE/bug-report-sse.md | 49 + .github/ISSUE_TEMPLATE/feature-request-sse.md | 33 + .gitignore | 4 + LICENSE | 201 ++ Makefile | 201 ++ Readme.md | 1145 ++++++++++++ backend/backend.go | 140 ++ backend/go.mod | 62 + backend/go.sum | 223 +++ backend/path_config.go | 294 +++ backend/path_help.go | 452 +++++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 +++ backend/path_hsm_key_bls.go | 259 +++ backend/path_hsm_key_camellia.go | 225 +++ backend/path_hsm_key_chacha20.go | 208 +++ backend/path_hsm_key_dsa.go | 273 +++ backend/path_hsm_key_ec.go | 270 +++ backend/path_hsm_key_ed.go | 271 +++ backend/path_hsm_key_import.go | 306 ++++ backend/path_hsm_key_rsa.go | 273 +++ backend/path_hsm_key_tdea.go | 208 +++ backend/path_hsm_key_with_name.go | 295 +++ backend/path_hsm_keys.go | 1359 ++++++++++++++ backend/path_hsm_operations.go | 1631 +++++++++++++++++ backend/path_hsm_requests.go | 298 +++ backend/path_mariadb_integration.go | 666 +++++++ client/client.go | 48 + client/client_tsb.go | 1023 +++++++++++ client/go.mod | 46 + client/go.sum | 203 ++ cmd/securosys-hsm/main.go | 49 + .../alpine3/docker-compose-alpine3.yml | 56 + docker-builder/build-in-docker.sh | 12 + etc/example/mariaDb.cfg | 22 + etc/example/policy.json | 93 + etc/release_notes/Release_Notes.md | 29 + go.mod | 80 + go.sum | 254 +++ go.work | 8 + go.work.sum | 164 ++ helpers/consts.go | 53 + helpers/functions.go | 234 +++ helpers/go.mod | 57 + helpers/go.sum | 223 +++ helpers/mariadb_structs.go | 82 + helpers/structs.go | 316 ++++ integrationTests/client/client.go | 30 + integrationTests/client/client_config.go | 15 + integrationTests/client/go.mod | 24 + integrationTests/client/go.sum | 58 + integrationTests/docker/docker-compose.yml | 39 + .../docker/docker-files/MariaDB_Dockerfile | 2 + .../docker/mysql-config/hashicorp.cnf | 18 + .../tests/a_enable_plugin_test.go | 48 + .../tests/b_config_plugin_test.go | 55 + .../tests/c_create_aes_key_test.go | 234 +++ .../tests/c_create_key_by_keyname_test.go | 93 + .../tests/c_create_rsa_key_test.go | 250 +++ .../tests/c_create_smart_rsa_key_test.go | 255 +++ .../tests/d_operations_on_key_test.go | 329 ++++ integrationTests/tests/go.mod | 6 + integrationTests/tests/go.sum | 0 project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 +++ testHelpers/test_client_tsb.go | 151 ++ testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 ++++++++ tests/go.mod | 66 + tests/go.sum | 223 +++ tests/go.work | 5 + tests/go.work.sum | 163 ++ tests/path_config_test.go | 153 ++ tests/path_hsm_key_aes_test.go | 133 ++ tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 ++ tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 ++ tests/path_hsm_key_tdea_test.go | 136 ++ tests/path_hsm_key_using_type_name_test.go | 245 +++ tests/path_hsm_keys_rotation_test.go | 836 +++++++++ tests/path_hsm_keys_test.go | 312 ++++ tests/path_hsm_operations_decrypt_test.go | 1001 ++++++++++ tests/path_hsm_operations_encrypt_test.go | 505 +++++ tests/path_hsm_operations_sign_test.go | 647 +++++++ tests/path_hsm_operations_unwrap_test.go | 675 +++++++ tests/path_hsm_operations_verify_test.go | 1438 +++++++++++++++ tests/path_hsm_operations_wrap_test.go | 242 +++ tests/path_hsm_requests_test.go | 299 +++ tests/path_mariadb_integration_test.go | 111 ++ 95 files changed, 23286 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-sse.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-sse.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 backend/path_mariadb_integration.go create mode 100644 client/client.go create mode 100644 client/client_tsb.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 cmd/securosys-hsm/main.go create mode 100644 docker-builder/alpine3/docker-compose-alpine3.yml create mode 100644 docker-builder/build-in-docker.sh create mode 100644 etc/example/mariaDb.cfg create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 go.work create mode 100644 go.work.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/mariadb_structs.go create mode 100644 helpers/structs.go create mode 100644 integrationTests/client/client.go create mode 100644 integrationTests/client/client_config.go create mode 100644 integrationTests/client/go.mod create mode 100644 integrationTests/client/go.sum create mode 100644 integrationTests/docker/docker-compose.yml create mode 100644 integrationTests/docker/docker-files/MariaDB_Dockerfile create mode 100644 integrationTests/docker/mysql-config/hashicorp.cnf create mode 100644 integrationTests/tests/a_enable_plugin_test.go create mode 100644 integrationTests/tests/b_config_plugin_test.go create mode 100644 integrationTests/tests/c_create_aes_key_test.go create mode 100644 integrationTests/tests/c_create_key_by_keyname_test.go create mode 100644 integrationTests/tests/c_create_rsa_key_test.go create mode 100644 integrationTests/tests/c_create_smart_rsa_key_test.go create mode 100644 integrationTests/tests/d_operations_on_key_test.go create mode 100644 integrationTests/tests/go.mod create mode 100644 integrationTests/tests/go.sum create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/go.work create mode 100644 tests/go.work.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go create mode 100644 tests/path_mariadb_integration_test.go diff --git a/.github/ISSUE_TEMPLATE/bug-report-sse.md b/.github/ISSUE_TEMPLATE/bug-report-sse.md new file mode 100644 index 0000000..40777e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-sse.md @@ -0,0 +1,49 @@ +--- +name: Bug report SSE +about: Create a report to help us improve +title: "[BUG] " +labels: '' +assignees: Peter-FNet + +--- + + + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment:** +* Vault Server Version (retrieve with `vault status`): +* Vault CLI Version (retrieve with `vault version`): +* Server Operating System/Architecture: + +Vault server configuration file(s): + +```hcl +# Paste your Vault config here. +# Be sure to scrub any sensitive values +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request-sse.md b/.github/ISSUE_TEMPLATE/feature-request-sse.md new file mode 100644 index 0000000..8264e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-sse.md @@ -0,0 +1,33 @@ +--- +name: Feature request SSE +about: Suggest an idea for this project +title: "[FEAT]" +labels: '' +assignees: Peter-FNet + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Explain any additional use-cases** +If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5375b60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +builds +vault +deploy +.gitlab-ci.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a142d1d --- /dev/null +++ b/Makefile @@ -0,0 +1,201 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` + +ifndef ARTIFACT_NAME +override ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +endif + +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + make release-alpine3 + echo "Finished!"; + +release-alpine3: + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-amd64 + make clean-docker-builder IMAGE=amd64/golang + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-i386 + make clean-docker-builder IMAGE=i386/golang + +clean-docker-builder: + @if [ "$$(docker images | grep '$(IMAGE)')" != "" ]; then \ + docker rmi -f $$(docker images | grep '$(IMAGE)' | awk '{ print $$3}') 2> /dev/null || true ; \ + fi; + docker volume prune -f + docker container prune -f + docker network prune -f + +run-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml up --build -d +clean-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml down --remove-orphans --rmi all + docker volume prune -f + docker container prune -f +integration-tests: + rm -fr integrationTests/docker/plugins/securosys-hsm + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -o integrationTests/docker/plugins/securosys-hsm cmd/securosys-hsm/main.go + make run-docker-test-container + + sleep 5 + go install github.com/jstemmer/go-junit-report/v2@latest + cd integrationTests/tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}integration_junit_report.xml -set-exit-code + + + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault_exec server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault_exec secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 15m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4828e0e --- /dev/null +++ b/Readme.md @@ -0,0 +1,1145 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Integrations](#integrations) + - [MariaDB](#mariadb) + - [Example usage](#mariadb-usage-example) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate and `keypath` with local PATH to the key. +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for Certificate authorization**: +```shell +$ vault write securosys-hsm/config +auth="CERT" +certpath="local_absolute_path_to_certificate.pem" +keypath="local_absolute_path_to_private.key" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=CERT' \ +--data-urlencode 'certpath=local_absolute_path_to_certificate.pem' \ +--data-urlencode 'keypath=local_absolute_path_to_private.pem' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Integrations +### MariaDB +Encryption on MariaDB can be enabled using existing plugin [Hashicorp Key Management Plugin](https://mariadb.com/kb/en/hashicorp-key-management-plugin/) +This integration stores generated secret in Secrets engine, encrypted by provided key. +**Supported Key Types**/**Algorithm** combinations: +| Key Type | Algorithm | +|----------|:-------------:| +| **RSA** |RSA_PADDING_OAEP_WITH_SHA512
RSA
RSA_PADDING_OAEP_WITH_SHA224
RSA_PADDING_OAEP_WITH_SHA256
RSA_PADDING_OAEP_WITH_SHA1
RSA_PADDING_OAEP
RSA_PADDING_OAEP_WITH_SHA384
RSA_NO_PADDING| +|**AES**|AES_GCM
AES_CTR
AES_ECB
AES_CBC_NO_PADDING
AES | +| **CHACHA20** | CHACHA20
CHACHA20_AEAD| +| **CAMELLIA** | CAMELLIA
CAMELLIA_CBC_NO_PADDING
CAMELLIA_ECB | +|**TDEA**| TDEA_CBC
TDEA_ECB
TDEA_CBC_NO_PADDING | + +>**Note** - Plugin supports **asynchronous decrypt operation** using key type **RSA** with **policy** with setup **ruleUse**. Using the key with policy will **stop** the decrypt operation and **wait for approvals** to be collected. + +There are a **serval steps** that is needed to be done before setup encryption on MariaDB +1) [Create / Register key](#manage-keys) into **Secrets Engine** +1) Generate new **secret** and encrypt it using stored key + ```shell + $ vault write securosys-hsm/integrations/mariadb/{secret-name} + keyName={key-name-from-secret-engine} + cipherAlgorithm={cipher-algorithm} + [additionalAuthenticationData={additional-authentication-data}] + [tagLength={tag-length}] + [password={password-for-a-key}] + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/integrations/mariadb/{secret-name} ' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName={key-name-from-secret-engine}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + >**Note** - Every request on this endpoint using same **key name** and **secret name** will **rotate secret** +1) The last step is add this configuration to **my.cfg** + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" + loose-hashicorp-key-management-token="{vault_access_token}" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + >**Note** - In **loose-hashicorp-key-management-vault-url** url need to ends with **&version=**. Plugin from **MariaDB** automatically add to end of url **number of secret version** +#### MariaDB usage example +This example using default configuration for **Hashicorp Vault dev server**. +| Data | Value | +|----------|:-------------:| +| **vault address** | https://localhost:8200 | +| **vault access token** | root | +1) **Create key** *MariaDBEncryptionKey* with key size *4096* with attributes at last "decrypt" equals *true* on HSM and store it as *mariadb_encryption_key* on **Secrets engine** + ```shell + $ vault write securosys-hsm/keys/rsa/mariadb_encryption_key + keyLabel="MariaDBEncryptionKey" + keySize=4096 + attributes='{"decrypt": true,"sign": false,"unwrap": false,"derive": true,"sensitive": true,"extractable": false,"modifiable": false,"copyable": false,"destroyable": true}' + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/keys/rsa/mariadb_encryption_key' \ + --header 'X-Vault-Token: root' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel=MariaDBEncryptionKey' \ + --data-urlencode 'keySize=4096' \ + --data-urlencode 'attributes={ + "decrypt": true, + "sign": false, + "unwrap": false, + "derive": true, + "sensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": false, + "copyable": false, + "destroyable": true + }' + ``` +1) Generate new **secret** called *mariadb_secret* and **encrypt it** using cipher algorithm *RSA* and stored key *mariadb_encryption_key* in **Secrets engine** + ```shell + $ vault write securosys-hsm/integrations/mariadb/mariadb_secret + keyName=mariadb_encryption_key + cipherAlgorithm=RSA + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret ' \ + --header 'X-Vault-Token: root' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName=mariadb_encryption_key' \ + --data-urlencode 'cipherAlgorithm=RSA' + ``` +3. Configure **MariaDB plugin** "Hashicorp Key Management" in database configuration in **my.cnf** + + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret/?key_name=mariadb_encryption_key&cipher_algorithm=RSA&version=" + loose-hashicorp-key-management-token="root" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + + + +--- +## Appendix +### Frequently Asked Questions +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..67cf38a --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,140 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + pathMariaDBIntegration(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..29a1fac --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,294 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + // "username": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Username", + // Sensitive: false, + // }, + // }, + // "password": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC' and when We did't fill BasicToken", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "Password", + // Sensitive: true, + // }, + // }, + // "basictoken": { + // Type: framework.TypeString, + // Description: "This parameter is needed if we set Auth='BASIC'. It must contain valid BasicToken. If We filled that field, then Username and Password will be ignored.", + // Required: false, + // DisplayAttrs: &framework.DisplayAttributes{ + // Name: "BasicToken", + // Sensitive: true, + // }, + // }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "keypath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to key", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "KeyPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if keypath, ok := data.GetOk("keypath"); ok { + config.KeyPath = keypath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing keypath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.KeyPath) + + if err != nil { + return nil, fmt.Errorf("Keypath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..8281fe0 --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,452 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKey(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..32954d9 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,1631 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keywrapEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string), map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result["keyVersion"] = keyEntry.CurrentVersion + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: result, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy, map[string]string{}) + } else { + requestId, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil, map[string]string{}) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString, nil) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, errReq, _ := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result["payload"].(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result["payload"] = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + return &logical.Response{ + Data: result, + }, nil +} diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..e24fe58 --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, err, _ := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} diff --git a/backend/path_mariadb_integration.go b/backend/path_mariadb_integration.go new file mode 100644 index 0000000..0101c1d --- /dev/null +++ b/backend/path_mariadb_integration.go @@ -0,0 +1,666 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for create Camellia Keys +func pathMariaDBIntegration(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "keyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsDelete, + }, + }, + HelpSynopsis: pathIntegrationMariaDBWriteHelpSynopsis, + HelpDescription: pathIntegrationMariaDBWriteHelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("version") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV1HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV1HelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV2HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV2HelpDescription, + }, + { + Pattern: "integrations/mariadb/?$", + Fields: map[string]*framework.FieldSchema{}, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsList, + }, + }, + HelpSynopsis: pathIntegrationMariaDBListHelpSynopsis, + HelpDescription: pathIntegrationMariaDBListHelpDescription, + }, + } +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "intergration/mariadb/") + if err != nil { + return nil, err + } + secrets := make([]string, 0, len(entries)) + secretsInfo := make(map[string]interface{}) + for _, name := range entries { + secrets = append(secrets, name) + secret, err := b.GetMariaDBSecret(ctx, req.Storage, name) + if err == nil { + secretsInfo[name] = map[string]interface{}{ + "KeyName": secret.KeyName, + "Version": secret.CurrentVersion, + "Created": secret.Created.Name, + "Updated": secret.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(secrets, secretsInfo), nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, errGet := b.GetMariaDBSecret(ctx, req.Storage, name) + if errGet != nil { + return nil, fmt.Errorf("error deleting mariadb secret: %w", errGet) + } + if storedSecret == nil { + return nil, fmt.Errorf("error deleting mariadb secret: secret with name %s not exists", d.Get("name").(string)) + + } + + err := req.Storage.Delete(ctx, "intergration/mariadb/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + rotate := false + if storedSecret != nil { + rotate = true + // return nil, fmt.Errorf("error secret with name: %s exists", name) + } else { + storedSecret = &helpers.MariaDBSecretEntry{} + + } + + keyName := d.Get("keyName").(string) + + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload := b64.StdEncoding.EncodeToString([]byte(helpers.GeneratePassword(32, false, false, false, true))) + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + sysView := b.System() + creator := helpers.Entity{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + creator.Aliases = entity.Aliases + creator.Id = entity.ID + creator.Name = entity.Name + creator.Date = time.Now().UTC() + + } else { + creator.Aliases = nil + creator.Id = "root" + creator.Name = "root" + creator.Date = time.Now().UTC() + + } + var messageAuthenticationCode *string = nil + if result["messageAuthenticationCode"] != nil { + temp := result["messageAuthenticationCode"].(string) + messageAuthenticationCode = &temp + } + var initializationVector *string = nil + if result["initializationVector"] != nil { + temp := result["initializationVector"].(string) + initializationVector = &temp + } + if !rotate { + storedSecret.InitSecret(keyName, keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + } else { + storedSecret.RotateSecret(keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result["encryptedPayload"].(string), creator) + + } + if err := SetMariaDBSecret(ctx, req.Storage, name, storedSecret); err != nil { + return nil, err + } + + response := map[string]interface{}{} + now := storedSecret.GetActiveVersion().Created.Date + version := storedSecret.GetActiveVersion().Version + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + query := d.Get("query").(string) + if strings.HasPrefix(query, "?") { + query = query[1:] + } + params, err := url.ParseQuery(query) + + if query == "" { + str := "" + for key, value := range req.Data { + str = str + key + "=" + value.(string) + "&" + } + str = str[:len(str)-1] + params, err = url.ParseQuery(str) + } + + if err != nil { + return nil, err + } + name := d.Get("name").(string) + + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + if storedSecret == nil { + return nil, fmt.Errorf("error secret with name: %s not exists", name) + } + + version := "1" + if params.Has("version") { + if !strings.Contains(params.Get("version"), "?version=") { + version = storedSecret.CurrentVersion + } else { + parts := strings.Split(params.Get("version"), "?version=") + version = "v" + parts[1] + } + } else { + ver, ok := d.GetOk("version") + if !ok { + return nil, fmt.Errorf("error: missing version") + } + version = ver.(string) + } + + if !params.Has("key_name") { + return nil, fmt.Errorf("key_name query param not exists") + } + keyEntry, err := b.GetKey(ctx, req.Storage, params.Get("key_name")) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + keyName := params.Get("key_name") + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + + if !helpers.ContainsKey(storedSecret.Versions, version) { + return nil, fmt.Errorf("Secret version %s is not exists.", version) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload := storedSecret.GetVersion(version).EncryptedSecret + + if !params.Has("cipher_algorithm") { + return nil, fmt.Errorf("cipher_algorithm query param not exists") + } + + cipherAlgorithm := params.Get("cipher_algorithm") + if keyEntry.KeyTypeName != "aes256-gcm96" && cipherAlgorithm == "" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVectorString := "" + if params.Has("initialization_vector") { + initializationVectorString = params.Get("initialization_vector") + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + passwordString := "" + if params.Has("password") { + passwordString = params.Get("password") + } + tagLengthInt := -1 + if params.Has("tag_length") { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + } + if keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationDataString := "" + if params.Has("aad") { + additionalAuthenticationDataString = params.Get("aad") + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationDataString) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData (param aad) is not valid base64 string") + } + } + client, err := b.GetClient(ctx, req.Storage) + async := false + decrypted := "" + if len(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + async = true + requestId, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString, map[string]string{"integration": "MariaDB Encrypt"}) + if errEnc != nil { + return nil, errEnc + } + var resp *helpers.RequestResponse + resp, _, _ = client.GetRequest(requestId) + for resp.Status == "PENDING" { + time.Sleep(1000) + resp, _, _ = client.GetRequest(requestId) + } + if resp.Status != "EXECUTED" { + return nil, fmt.Errorf("error on async decrypt. Expected Status '%s' got '%s'", "EXECUTED", resp.Status) + } + decrypted = resp.Result + + } + } + } + if !async { + resultSync, errEnc := client.Decrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + decrypted = resultSync["payload"].(string) + } + + if cipherAlgorithm == "AES_ECB" || + cipherAlgorithm == "AES_CBC_NO_PADDING" || + cipherAlgorithm == "CAMELLIA_ECB" || + cipherAlgorithm == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + decoded, _ := base64.StdEncoding.DecodeString(decrypted) + response := map[string]interface{}{} + response["data"] = map[string]interface{}{"data": string(decoded)} + now := storedSecret.GetVersion(version).Created.Date + + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} + +// This function helps with saving key in Secrets Engine +func SetMariaDBSecret(ctx context.Context, s logical.Storage, name string, secretEntry *helpers.MariaDBSecretEntry) error { + entry, err := logical.StorageEntryJSON("intergration/mariadb/"+name, secretEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage secret") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetMariaDBSecret(ctx context.Context, s logical.Storage, name string) (*helpers.MariaDBSecretEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "intergration/mariadb/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var secret helpers.MariaDBSecretEntry + + if err := entry.DecodeJSON(&secret); err != nil { + return nil, err + } + return &secret, nil +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..e49b33b --- /dev/null +++ b/client/client.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + c, err := NewTSBClient(mappedConfig) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/client_tsb.go b/client/client_tsb.go new file mode 100644 index 0000000..b50c7e2 --- /dev/null +++ b/client/client_tsb.go @@ -0,0 +1,1023 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "strconv" + "time" + + helpers "securosys.ch/helpers" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` +} + +// Function inicialize new client for accessing TSB +func NewTSBClient(data map[string]string) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: data["restapi"], + Auth: AuthStruct{ + AuthType: data["auth"], + CertPath: data["certpath"], + KeyPath: data["keypath"], + BearerToken: data["bearertoken"], + BasicToken: data["basictoken"], + Username: data["username"], + Password: data["password"], + }, + } + + return &c, nil +} + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (string, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + ` + passwordString + ` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy, customMetaData map[string]string) (string, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Modify", additionalMetaDataInfo, customMetaData) + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "modifyRequest":{ + "modifyKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + ` + policyString + `} + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["modifyKeyRequestId"].(string), nil + +} + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (map[string]interface{}, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString := "" + if len(keyToBeWrappedPasswordJson) > 2 { + keyToBeWrappedPasswordString = `"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString := "" + if len(wrapKeyPasswordJson) > 2 { + wrapKeyPasswordString = `"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + ` + keyToBeWrappedPasswordString + ` + "wrapKeyName": "` + wrapKeyName + `", + ` + wrapKeyPasswordString + ` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "encryptedPayload") || !helpers.ContainsKey(response, "initializationVector") { + return nil, fmt.Errorf("Error on encrypt response. Need encryptedPayload, initializationVector found %s", string(body[:])) + } + return response, nil + +} + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + ` + passwordString + ` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Block", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + "blockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["blockKeyRequestId"].(string), nil + +} + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + ` + passwordString + ` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnBlock", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + "unblockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unblockKeyRequestId"].(string), nil +} + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signature") { + return nil, fmt.Errorf("Error on sign response. Need signature found %s", string(body[:])) + } + + return response, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Sign", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["signRequestId"].(string), nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("Decrypt", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["decryptRequestId"].(string), nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "payload") { + return nil, fmt.Errorf("Error on decrypt response. Need payload found %s", string(body[:])) + } + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + ` + passwordString + ` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, error, int) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, err, 500 + } + body, errRes, code := c.doRequest(req) + if errRes != nil { + return nil, errRes, code + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, errJSON, code + } + return &requestResponse, nil, code +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + ` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req) + + return nil + +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) error { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return err + } + _, errReq, code := c.doRequest(req) + if code == 404 || code == 500 { + return nil + } + if errReq != nil { + return errReq + } + return nil + +} + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString := "" + if len(charsNewPasswordJson) > 2 { + newPasswordString = `"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + newPasswordString + ` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + passwordString + ` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} +func (c *TSBClient) CheckConnection() (string, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", err + } + body, errReq, _ := c.doRequest(req) + if errReq != nil { + return string(body[:]), errReq + } + return string(body[:]), nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy, customMetaData map[string]string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := helpers.PrepareMetaData("UnWrap", additionalMetaDataInfo, customMetaData) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": "` + metaDataSignature + `"` + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, errRes, _ := c.doRequest(req) + if errRes != nil { + return "", errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return result["unwrapRequestId"].(string), nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, err, _ := c.doRequest(req) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + clientTLSCert, err := tls.LoadX509KeyPair(c.Auth.CertPath, c.Auth.KeyPath) + if err != nil { + log.Fatalf("Error loading certificate and key file: %v", err) + return nil, err, 0 + } + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + InsecureSkipVerify: true, + Certificates: []tls.Certificate{clientTLSCert}, + }, + } + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/docker-builder/alpine3/docker-compose-alpine3.yml b/docker-builder/alpine3/docker-compose-alpine3.yml new file mode 100644 index 0000000..1190d88 --- /dev/null +++ b/docker-builder/alpine3/docker-compose-alpine3.yml @@ -0,0 +1,56 @@ + version: "3.3" + services: + golang-builder-alpine3-amd64: + platform: linux/amd64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=amd64 + image: amd64/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-amd64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-i386: + platform: linux/i386 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=386 + image: i386/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-i386 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-arm64: + platform: linux/arm64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=arm64 + image: arm64v8/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-arm64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" \ No newline at end of file diff --git a/docker-builder/build-in-docker.sh b/docker-builder/build-in-docker.sh new file mode 100644 index 0000000..adc15b2 --- /dev/null +++ b/docker-builder/build-in-docker.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd .. +echo "Build ${ARTIFACT_NAME} in ${DOCKER_OS}_${DOCKER_ARCH}"; + cd /src + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; + cd builds; + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; + zip -9 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; + shasum -a 256 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; + cd ..; + rm builds/securosys-hsm; + rm builds/securosys-hsm_SHA256SUM; \ No newline at end of file diff --git a/etc/example/mariaDb.cfg b/etc/example/mariaDb.cfg new file mode 100644 index 0000000..298e73a --- /dev/null +++ b/etc/example/mariaDb.cfg @@ -0,0 +1,22 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" +loose-hashicorp-key-management-token="{vault_access_token}" +loose-hashicorp-key-management-check-kv-version="off" +#max timeout is 86400 seconds +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +#1 year in miliseconds +loose-hashicorp-key-management-cache-timeout=31556952000 +#1 year in miliseconds +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +#Example of innodb config +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = ON +innodb_encrypt_log = ON +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 \ No newline at end of file diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..8e00e02 --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,93 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..6eebb05 --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,29 @@ +# Securosys Hashicorp Vault Secrets Engine 1.1.0 +Issued: Dec, 6, 2023 +## Documentation Change +- Update Readme.md - added information about supporting and how to configure encryption on MariaDB +## Feature +- Added integration with MariaDB encryption +## Bugfix +- Fixed authentication with TSB using mTLS + +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build/ + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2d78c0c --- /dev/null +++ b/go.mod @@ -0,0 +1,80 @@ +module secretengine + +go 1.21 + +toolchain go1.21.2 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers + +replace securosys.ch/tests => ./tests + +replace securosys.ch/integration/client => ./integrationTests/client + +replace securosys.ch/integration/tests => ./integrationTests/tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/frankban/quicktest v1.14.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afae25d --- /dev/null +++ b/go.sum @@ -0,0 +1,254 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work new file mode 100644 index 0000000..ad36518 --- /dev/null +++ b/go.work @@ -0,0 +1,8 @@ +go 1.21 + +use ( + ./ + ./backend + ./integrationTests/client + ./integrationTests/tests +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..976ca94 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,164 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..4ab2d92 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..bdc47e4 --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/sha256" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "math/rand" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + approval.TypeOfKey = "public_key" + approval.Name = name + approval.Value = element + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} +func GetVersionNumber(version string) int { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + return versionInt +} +func GetVersionString(version string) string { + return strings.Replace(version, "v", "", 1) +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string, customMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + for key, value := range customMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + specialBytes = "!@#$%^&*()_+-=[]{}\\|;':\",.<>/?`~" + numBytes = "0123456789" + hexDecimalBytes = "0123456789ABCDEF" +) + +func GeneratePassword(length int, useLetters bool, useSpecial bool, useNum bool, useHexadecimal bool) string { + rand.Seed(time.Now().UnixNano()) + b := make([]byte, length) + arrayForRandom := make([]byte, 0) + if useLetters { + arrayForRandom = append(arrayForRandom, letterBytes...) + } + if useSpecial { + arrayForRandom = append(arrayForRandom, specialBytes...) + } + if useNum { + arrayForRandom = append(arrayForRandom, numBytes...) + } + if useHexadecimal { + arrayForRandom = append(arrayForRandom, hexDecimalBytes...) + + } + + for i := range b { + b[i] = arrayForRandom[rand.Intn(len(arrayForRandom))] + } + return string(b) +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/mariadb_structs.go b/helpers/mariadb_structs.go new file mode 100644 index 0000000..97210ac --- /dev/null +++ b/helpers/mariadb_structs.go @@ -0,0 +1,82 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// INTEGRATION MARIADB STRUCTS + +type MariaDBSecretEntry struct { + KeyName string `json:"keyName"` + Versions map[string]MariaDBSecretVersion `json:"secretVersions"` + CurrentVersion string `json:"defaultVersion"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +// Struct of keys stored inside the Vault +type MariaDBSecretVersion struct { + KeyVersion string `json:"keyVersion"` + EncryptedSecret string `json:"encryptedSecret"` + MessageAuthenticationCode *string `json:"messageAuthenticationCode"` + InitializationVector *string `json:"initializationVector"` + Version string `json:"version"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (s *MariaDBSecretEntry) InitSecret(keyName string, keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, creator Entity) { + s.CurrentVersion = "v1" + s.KeyName = keyName + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = "v1" + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = creator + secretVersion.Updated = creator + s.Created = creator + s.Updated = creator + s.Versions = make(map[string]MariaDBSecretVersion) + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) RotateSecret(keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, updater Entity) { + newSecretVersion := GetNewVersion(s.CurrentVersion) + s.CurrentVersion = newSecretVersion + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = newSecretVersion + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = updater + secretVersion.Updated = updater + s.Updated = updater + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) GetActiveVersion() MariaDBSecretVersion { + return s.Versions[s.CurrentVersion] +} +func (s *MariaDBSecretEntry) GetVersion(keyVersion string) MariaDBSecretVersion { + return s.Versions[keyVersion] +} + +// END INTEGRATION MARIADB STRUCTS diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..9782f2d --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,316 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + RestApi string `json:"restapi"` +} + +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} + +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} + +// Struct of keys stored inside the Vault +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) { + list[approval.Name] = approval.Value + } + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/integrationTests/client/client.go b/integrationTests/client/client.go new file mode 100644 index 0000000..70d4bee --- /dev/null +++ b/integrationTests/client/client.go @@ -0,0 +1,30 @@ +package integrationClient + +import ( + "fmt" + "log" + "os" + "time" + + "github.com/hashicorp/vault-client-go" +) + +func InitVaultClient() (*vault.Client){ + + // prepare a client with the given base address + client, err := vault.New( + vault.WithAddress(VaultConfig.Url+":"+fmt.Sprint(VaultConfig.Port)), + vault.WithRequestTimeout(30*time.Second), + ) + if err != nil { + log.Fatal(err) + os.Exit(1); + } + + // authenticate with a root token (insecure) + if err := client.SetToken(VaultConfig.RootToken); err != nil { + log.Fatal(err) + os.Exit(1); + } + return client; +} \ No newline at end of file diff --git a/integrationTests/client/client_config.go b/integrationTests/client/client_config.go new file mode 100644 index 0000000..148f2a9 --- /dev/null +++ b/integrationTests/client/client_config.go @@ -0,0 +1,15 @@ +package integrationClient + +type VaultClientConfig struct { + Port int + Url string + RootToken string + SecretsEnginePath string +} + +var VaultConfig VaultClientConfig=VaultClientConfig{ + Port: 8251, + Url: "http://127.0.0.1", + RootToken: "root", + SecretsEnginePath: "securosys-hsm", +} \ No newline at end of file diff --git a/integrationTests/client/go.mod b/integrationTests/client/go.mod new file mode 100644 index 0000000..02d12cd --- /dev/null +++ b/integrationTests/client/go.mod @@ -0,0 +1,24 @@ +module securosys.ch/integration/client + +go 1.21 + +toolchain go1.21.2 + +require github.com/hashicorp/vault-client-go v0.4.2 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stretchr/testify v1.8.2 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect +) diff --git a/integrationTests/client/go.sum b/integrationTests/client/go.sum new file mode 100644 index 0000000..3a52bd0 --- /dev/null +++ b/integrationTests/client/go.sum @@ -0,0 +1,58 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/vault-client-go v0.4.2 h1:XeUXb5jnDuCUhC8HRpkdGPLh1XtzXmiOnF0mXEbARxI= +github.com/hashicorp/vault-client-go v0.4.2/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integrationTests/docker/docker-compose.yml b/integrationTests/docker/docker-compose.yml new file mode 100644 index 0000000..1b00ff4 --- /dev/null +++ b/integrationTests/docker/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.0" +name: hashicorp-vault-test-containers +services: + hashicorp-vault-test: + image: hashicorp/vault:latest + container_name: "hashicorp-vault-test" + environment: + VAULT_DEV_ROOT_TOKEN_ID: root + VAULT_ADDR: 'https://0.0.0.0:8251' + VAULT_LOCAL_CONFIG: '{"listener": [{"tcp":{"address": "0.0.0.0:8251","tls_disable":"1"}}], "default_lease_ttl": "168h", "max_lease_ttl": "720h"}, "ui": true}' + volumes: + - ./plugins/:/vault/plugins + cap_add: + - IPC_LOCK + healthcheck: + retries: 5 + ports: + - "8251:8251" + privileged: true + command: server -dev -dev-root-token-id=root -dev-plugin-dir=/vault/plugins + networks: + - web + mariadb-test-integration: + build: + dockerfile: ./docker-files/MariaDB_Dockerfile + container_name: "mariadb-test-integration" + restart: always + environment: + MARIADB_ROOT_PASSWORD: example + volumes: + - ./mysql-config:/etc/mysql/conf.d + - ./db:/var/lib/mysql + networks: + - web + +networks: + web: + external: true + \ No newline at end of file diff --git a/integrationTests/docker/docker-files/MariaDB_Dockerfile b/integrationTests/docker/docker-files/MariaDB_Dockerfile new file mode 100644 index 0000000..7e5d37a --- /dev/null +++ b/integrationTests/docker/docker-files/MariaDB_Dockerfile @@ -0,0 +1,2 @@ +FROM mariadb:latest +RUN apt-get update && apt-get install -y mariadb-plugin-hashicorp-key-management diff --git a/integrationTests/docker/mysql-config/hashicorp.cnf b/integrationTests/docker/mysql-config/hashicorp.cnf new file mode 100644 index 0000000..d628bc7 --- /dev/null +++ b/integrationTests/docker/mysql-config/hashicorp.cnf @@ -0,0 +1,18 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="http://192.168.96.3:8251/v1/securosys-hsm/integrations/mariadb/test_async/?cipher_algorithm=RSA&key_name=rsa_with_policy&version=" +loose-hashicorp-key-management-token="root" +loose-hashicorp-key-management-check-kv-version="off" +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +loose-hashicorp-key-management-cache-timeout=31556952000 +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = OFF +innodb_encrypt_log = OFF +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 diff --git a/integrationTests/tests/a_enable_plugin_test.go b/integrationTests/tests/a_enable_plugin_test.go new file mode 100644 index 0000000..d16575a --- /dev/null +++ b/integrationTests/tests/a_enable_plugin_test.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "testing" + + "github.com/hashicorp/vault-client-go/schema" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestEnablePlugin(t *testing.T) { + + t.Run("A.1 Test Enable Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.System.MountsEnableSecretsEngine(ctx,integrationClient.VaultConfig.SecretsEnginePath,schema.MountsEnableSecretsEngineRequest{ + Type: "securosys-hsm", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/b_config_plugin_test.go b/integrationTests/tests/b_config_plugin_test.go new file mode 100644 index 0000000..d777766 --- /dev/null +++ b/integrationTests/tests/b_config_plugin_test.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfigPlugin(t *testing.T) { + + t.Run("B.1 Test Config Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/config",testHelpers.ConfigParams) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data["result"]==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s","null").Error()) + } + + if(!strings.Contains(resp.Data["result"].(string),"Connection successful:")){ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s",resp.Data["result"]).Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_aes_key_test.go b/integrationTests/tests/c_create_aes_key_test.go new file mode 100644 index 0000000..ccffd1b --- /dev/null +++ b/integrationTests/tests/c_create_aes_key_test.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateAESKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_aes"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_aes got %s","null").Error()) + } + }) + t.Run("C.3 Read AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["secretKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Key Secret got %s","null").Error()) + } + }) + t.Run("C.8 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_key_by_keyname_test.go b/integrationTests/tests/c_create_key_by_keyname_test.go new file mode 100644 index 0000000..285e47c --- /dev/null +++ b/integrationTests/tests/c_create_key_by_keyname_test.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateKeyByKeyNamePlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with label integrationTestKeyRSAName using name rsa-2048", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/type/rsa-2048/integration_test_key_rsa_name",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSAName", + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSAName"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSAName",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSAName_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test Remove Key RSA Key with name integrationTestKeyRSAName", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa_name",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_rsa_key_test.go b/integrationTests/tests/c_create_rsa_key_test.go new file mode 100644 index 0000000..90c1a10 --- /dev/null +++ b/integrationTests/tests/c_create_rsa_key_test.go @@ -0,0 +1,250 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["publicKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Public Key got %s","null").Error()) + } + if(resp.Data["privateKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Private Key got %s","null").Error()) + } + }) + t.Run("C.8 Update password RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/update-password",map[string]interface{}{ + "password":"", + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Test Remove Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_smart_rsa_key_test.go b/integrationTests/tests/c_create_smart_rsa_key_test.go new file mode 100644 index 0000000..dfdd792 --- /dev/null +++ b/integrationTests/tests/c_create_smart_rsa_key_test.go @@ -0,0 +1,255 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateSmartRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_smart_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_smart_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Block Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/block",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.8 UnBlock Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/unblock",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Update password Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/update-password",map[string]interface{}{ + "password":nil, + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/d_operations_on_key_test.go b/integrationTests/tests/d_operations_on_key_test.go new file mode 100644 index 0000000..8dc951b --- /dev/null +++ b/integrationTests/tests/d_operations_on_key_test.go @@ -0,0 +1,329 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestOperationsOnKeyPlugin(t *testing.T) { + + t.Run("D.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.2 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.3 Test Encrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.4 Test Encrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.5 Test Decrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.6 Test Decrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_key_aes",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.7 Test Sign using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + }) + t.Run("D.8 Test Verify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/verify/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "keyVersion":"v1", + "signatureAlgorithm":"SHA256_WITH_RSA", + "signature":resp.Data["signature"].(string), + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid got %s","null").Error()) + } + if(resp.Data["signatureValid"]==false){ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid %s got %s","true",resp.Data["signatureValid"]).Error()) + } + }) + t.Run("D.9 Test Modify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/modify",map[string]interface{}{ + "simplePolicy":`{"test":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnydX62tLYNF+Op1SRnX6avkkyQWlpYPagH85zxaGnMlZoMioqgjSOCuRvjaP7Y5noPMYayp3gJ2PwLXvw9+JlnL+iwklOcpONSa6gDoCDsk26DOoY0ELEPaGdW61mc2bj2hOQE0GEpPsRywJoRLS3B2e8bqRfAniAfGsUq3MK09iL5YOCuUCHCUiR9iZMSt0+Ek/kE4TrazbOCev1g6Ux2vOyTuQ6mF3wVuqwd8RhfvlNNKXbD2GD/jR3BwuhaodwzRPmDyDQPmEMwornxrMLavTcC+Igb4k5qol0Di6Oq8axpBvrH7KlxHT11Wd+ALKCsqoPSGxcIbd6TdN+ag9AQIDAQAB"}`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.11 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/go.mod b/integrationTests/tests/go.mod new file mode 100644 index 0000000..02bc999 --- /dev/null +++ b/integrationTests/tests/go.mod @@ -0,0 +1,6 @@ +module securosys.ch/integration/tests + +replace securosys.ch/integration/client => ./../client +replace securosys.ch/test-helpers => ./../../testHelpers + +go 1.19 diff --git a/integrationTests/tests/go.sum b/integrationTests/tests/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..0111058 --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.1.0 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..e82c1e7 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,151 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, err, _ := c.doRequest(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, err, code := c.doRequest(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TestTSBClient) doRequest(req *http.Request) ([]byte, error, int) { + // req.Header.Set("Authorization", c.Token) + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err, res.StatusCode + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err, res.StatusCode + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, fmt.Errorf("status: %d, body: %s", res.StatusCode, body), res.StatusCode + } + + return body, err, res.StatusCode +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..b55e030 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_API_URL", + "auth": "TOKEN", + "bearertoken": "TSB_BEARER_TOKEN", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/go.work b/tests/go.work new file mode 100644 index 0000000..7c33c4f --- /dev/null +++ b/tests/go.work @@ -0,0 +1,5 @@ +go 1.21 + +use ( + ./ +) \ No newline at end of file diff --git a/tests/go.work.sum b/tests/go.work.sum new file mode 100644 index 0000000..aff7933 --- /dev/null +++ b/tests/go.work.sum @@ -0,0 +1,163 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6b34f8c --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..3526595 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,299 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} diff --git a/tests/path_mariadb_integration_test.go b/tests/path_mariadb_integration_test.go new file mode 100644 index 0000000..b9b856e --- /dev/null +++ b/tests/path_mariadb_integration_test.go @@ -0,0 +1,111 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIntegrationMariaDB(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("A) add config", testEnv.AddConfig) + + t.Run("B) Test Creating RSA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + }) + t.Run("C)Add generate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("D)Read secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "integrations/mariadb/test/v1?key_name=custom_rsa_2048&cipher_algorithm=RSA", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("E) Rotate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("F) List secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "integrations/mariadb", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("G) Delete secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "integrations/mariadb/test", + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("H) Test Delete RSA key", func(t *testing.T) { + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + assert.NoError(t, err) + }) +} From 05511e0c89d1a6d72c488f7929922937a4e6d62e Mon Sep 17 00:00:00 2001 From: GitLab Runner Date: Tue, 27 Aug 2024 21:36:27 +0200 Subject: [PATCH 16/16] Release v.1.2.0 --- .github/ISSUE_TEMPLATE/bug-report-sse.md | 49 + .github/ISSUE_TEMPLATE/feature-request-sse.md | 33 + .gitignore | 4 + LICENSE | 201 ++ Makefile | 200 ++ Readme.md | 1145 ++++++++ backend/backend.go | 140 + backend/go.mod | 62 + backend/go.sum | 223 ++ backend/path_config.go | 291 ++ backend/path_help.go | 483 ++++ backend/path_hsm_health.go | 63 + backend/path_hsm_key_aes.go | 213 ++ backend/path_hsm_key_bls.go | 259 ++ backend/path_hsm_key_camellia.go | 225 ++ backend/path_hsm_key_chacha20.go | 208 ++ backend/path_hsm_key_dsa.go | 273 ++ backend/path_hsm_key_ec.go | 270 ++ backend/path_hsm_key_ed.go | 271 ++ backend/path_hsm_key_import.go | 306 +++ backend/path_hsm_key_rsa.go | 273 ++ backend/path_hsm_key_tdea.go | 208 ++ backend/path_hsm_key_with_name.go | 295 ++ backend/path_hsm_keys.go | 1359 +++++++++ backend/path_hsm_operations.go | 2421 +++++++++++++++++ backend/path_hsm_requests.go | 298 ++ backend/path_mariadb_integration.go | 666 +++++ client/TSBClient.go | 353 +++ client/additionalMethods.go | 46 + client/block.go | 103 + client/certs.go | 446 +++ client/client.go | 64 + client/encrypt.go | 193 ++ client/go.mod | 46 + client/go.sum | 203 ++ client/go.work | 6 + client/go.work.sum | 1 + client/health.go | 35 + client/key.go | 256 ++ client/modify.go | 106 + client/requests.go | 63 + client/sign.go | 153 ++ client/unblock.go | 101 + client/wrap.go | 171 ++ cmd/securosys-hsm/main.go | 49 + .../alpine3/docker-compose-alpine3.yml | 56 + docker-builder/build-in-docker.sh | 12 + etc/example/mariaDb.cfg | 22 + etc/example/policy.json | 93 + etc/release_notes/Release_Notes.md | 34 + go.mod | 80 + go.sum | 254 ++ go.work | 8 + go.work.sum | 164 ++ helpers/consts.go | 59 + helpers/functions.go | 286 ++ helpers/go.mod | 57 + helpers/go.sum | 223 ++ helpers/mariadb_structs.go | 93 + helpers/structs.go | 417 +++ integrationTests/client/client.go | 30 + integrationTests/client/client_config.go | 15 + integrationTests/client/go.mod | 24 + integrationTests/client/go.sum | 58 + integrationTests/docker/docker-compose.yml | 40 + .../docker/docker-files/MariaDB_Dockerfile | 2 + .../docker/mysql-config/hashicorp.cnf | 18 + .../tests/a_enable_plugin_test.go | 48 + .../tests/b_config_plugin_test.go | 55 + .../tests/c_create_aes_key_test.go | 234 ++ .../tests/c_create_key_by_keyname_test.go | 93 + .../tests/c_create_rsa_key_test.go | 250 ++ .../tests/c_create_smart_rsa_key_test.go | 255 ++ .../tests/d_operations_on_key_test.go | 329 +++ integrationTests/tests/go.mod | 6 + integrationTests/tests/go.sum | 0 project.properties | 1 + testHelpers/go.mod | 61 + testHelpers/go.sum | 225 ++ testHelpers/test_client_tsb.go | 167 ++ testHelpers/test_config.go | 27 + testHelpers/test_functions.go | 740 +++++ tests/go.mod | 66 + tests/go.sum | 223 ++ tests/go.work | 5 + tests/go.work.sum | 182 ++ tests/path_config_test.go | 153 ++ tests/path_hsm_key_aes_test.go | 133 + tests/path_hsm_key_bls_test.go | 69 + tests/path_hsm_key_camellia_test.go | 69 + tests/path_hsm_key_chacha20_test.go | 70 + tests/path_hsm_key_dsa_test.go | 100 + tests/path_hsm_key_ec_test.go | 134 + tests/path_hsm_key_ed_test.go | 70 + tests/path_hsm_key_import_test.go | 83 + tests/path_hsm_key_rsa_test.go | 166 ++ tests/path_hsm_key_tdea_test.go | 136 + tests/path_hsm_key_using_type_name_test.go | 245 ++ tests/path_hsm_keys_rotation_test.go | 836 ++++++ tests/path_hsm_keys_test.go | 312 +++ tests/path_hsm_operations_decrypt_test.go | 1001 +++++++ tests/path_hsm_operations_encrypt_test.go | 505 ++++ tests/path_hsm_operations_sign_test.go | 647 +++++ tests/path_hsm_operations_unwrap_test.go | 675 +++++ tests/path_hsm_operations_verify_test.go | 1438 ++++++++++ tests/path_hsm_operations_wrap_test.go | 242 ++ tests/path_hsm_requests_test.go | 301 ++ tests/path_mariadb_integration_test.go | 111 + 108 files changed, 25342 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-sse.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request-sse.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 backend/backend.go create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/path_config.go create mode 100644 backend/path_help.go create mode 100644 backend/path_hsm_health.go create mode 100644 backend/path_hsm_key_aes.go create mode 100644 backend/path_hsm_key_bls.go create mode 100644 backend/path_hsm_key_camellia.go create mode 100644 backend/path_hsm_key_chacha20.go create mode 100644 backend/path_hsm_key_dsa.go create mode 100644 backend/path_hsm_key_ec.go create mode 100644 backend/path_hsm_key_ed.go create mode 100644 backend/path_hsm_key_import.go create mode 100644 backend/path_hsm_key_rsa.go create mode 100644 backend/path_hsm_key_tdea.go create mode 100644 backend/path_hsm_key_with_name.go create mode 100644 backend/path_hsm_keys.go create mode 100644 backend/path_hsm_operations.go create mode 100644 backend/path_hsm_requests.go create mode 100644 backend/path_mariadb_integration.go create mode 100644 client/TSBClient.go create mode 100644 client/additionalMethods.go create mode 100644 client/block.go create mode 100644 client/certs.go create mode 100644 client/client.go create mode 100644 client/encrypt.go create mode 100644 client/go.mod create mode 100644 client/go.sum create mode 100644 client/go.work create mode 100644 client/go.work.sum create mode 100644 client/health.go create mode 100644 client/key.go create mode 100644 client/modify.go create mode 100644 client/requests.go create mode 100644 client/sign.go create mode 100644 client/unblock.go create mode 100644 client/wrap.go create mode 100644 cmd/securosys-hsm/main.go create mode 100644 docker-builder/alpine3/docker-compose-alpine3.yml create mode 100644 docker-builder/build-in-docker.sh create mode 100644 etc/example/mariaDb.cfg create mode 100644 etc/example/policy.json create mode 100644 etc/release_notes/Release_Notes.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 go.work create mode 100644 go.work.sum create mode 100644 helpers/consts.go create mode 100644 helpers/functions.go create mode 100644 helpers/go.mod create mode 100644 helpers/go.sum create mode 100644 helpers/mariadb_structs.go create mode 100644 helpers/structs.go create mode 100644 integrationTests/client/client.go create mode 100644 integrationTests/client/client_config.go create mode 100644 integrationTests/client/go.mod create mode 100644 integrationTests/client/go.sum create mode 100644 integrationTests/docker/docker-compose.yml create mode 100644 integrationTests/docker/docker-files/MariaDB_Dockerfile create mode 100644 integrationTests/docker/mysql-config/hashicorp.cnf create mode 100644 integrationTests/tests/a_enable_plugin_test.go create mode 100644 integrationTests/tests/b_config_plugin_test.go create mode 100644 integrationTests/tests/c_create_aes_key_test.go create mode 100644 integrationTests/tests/c_create_key_by_keyname_test.go create mode 100644 integrationTests/tests/c_create_rsa_key_test.go create mode 100644 integrationTests/tests/c_create_smart_rsa_key_test.go create mode 100644 integrationTests/tests/d_operations_on_key_test.go create mode 100644 integrationTests/tests/go.mod create mode 100644 integrationTests/tests/go.sum create mode 100644 project.properties create mode 100644 testHelpers/go.mod create mode 100644 testHelpers/go.sum create mode 100644 testHelpers/test_client_tsb.go create mode 100644 testHelpers/test_config.go create mode 100644 testHelpers/test_functions.go create mode 100644 tests/go.mod create mode 100644 tests/go.sum create mode 100644 tests/go.work create mode 100644 tests/go.work.sum create mode 100644 tests/path_config_test.go create mode 100644 tests/path_hsm_key_aes_test.go create mode 100644 tests/path_hsm_key_bls_test.go create mode 100644 tests/path_hsm_key_camellia_test.go create mode 100644 tests/path_hsm_key_chacha20_test.go create mode 100644 tests/path_hsm_key_dsa_test.go create mode 100644 tests/path_hsm_key_ec_test.go create mode 100644 tests/path_hsm_key_ed_test.go create mode 100644 tests/path_hsm_key_import_test.go create mode 100644 tests/path_hsm_key_rsa_test.go create mode 100644 tests/path_hsm_key_tdea_test.go create mode 100644 tests/path_hsm_key_using_type_name_test.go create mode 100644 tests/path_hsm_keys_rotation_test.go create mode 100644 tests/path_hsm_keys_test.go create mode 100644 tests/path_hsm_operations_decrypt_test.go create mode 100644 tests/path_hsm_operations_encrypt_test.go create mode 100644 tests/path_hsm_operations_sign_test.go create mode 100644 tests/path_hsm_operations_unwrap_test.go create mode 100644 tests/path_hsm_operations_verify_test.go create mode 100644 tests/path_hsm_operations_wrap_test.go create mode 100644 tests/path_hsm_requests_test.go create mode 100644 tests/path_mariadb_integration_test.go diff --git a/.github/ISSUE_TEMPLATE/bug-report-sse.md b/.github/ISSUE_TEMPLATE/bug-report-sse.md new file mode 100644 index 0000000..40777e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-sse.md @@ -0,0 +1,49 @@ +--- +name: Bug report SSE +about: Create a report to help us improve +title: "[BUG] " +labels: '' +assignees: Peter-FNet + +--- + + + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment:** +* Vault Server Version (retrieve with `vault status`): +* Vault CLI Version (retrieve with `vault version`): +* Server Operating System/Architecture: + +Vault server configuration file(s): + +```hcl +# Paste your Vault config here. +# Be sure to scrub any sensitive values +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request-sse.md b/.github/ISSUE_TEMPLATE/feature-request-sse.md new file mode 100644 index 0000000..8264e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-sse.md @@ -0,0 +1,33 @@ +--- +name: Feature request SSE +about: Suggest an idea for this project +title: "[FEAT]" +labels: '' +assignees: Peter-FNet + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Explain any additional use-cases** +If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5375b60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +builds +vault +deploy +.gitlab-ci.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e5c409f --- /dev/null +++ b/Makefile @@ -0,0 +1,200 @@ +UNAME = $(shell uname -s) +.DEFAULT_GOAL := all +TEST_RESULT_PATH = $(PWD)/ +GOPATH=`go env GOPATH` + +ifndef ARTIFACT_NAME +override ARTIFACT_NAME = HCVault_Plugin-Secrets-Engine +endif + +all: fmt build start +release: + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" == "windows" ] ; then\ + echo "Build windows"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "" ] && [ "$(ARCH)" == "" ] && [ "$(UNAME)" != "windows" ] ; then\ + echo "Build $(UNAME)"; \ + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + exit 0; \ + fi; + @if [ "$(OS)" == "windows" ]; then\ + echo "Build windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + else\ + echo "Build ${OS} in ARCH: ${ARCH}"; \ + CGO_ENABLED=0 GOOS=${OS} GOARCH="${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_${OS}_${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + echo "Finished!"; \ + fi; + +release-all: + rm -rf builds + for ARCH in amd64 arm64; do\ + echo "Build MacOS in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=darwin GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_darwin_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64; do\ + echo "Build Windows in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=windows GOARCH="$${ARCH}" go build -o builds/securosys-hsm.exe cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm.exe > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_windows_$${ARCH}.zip securosys-hsm.exe securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_windows_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm.exe; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm arm64; do\ + echo "Build Linux in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=linux GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_linux_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_linux_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build FreeBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=freebsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_freebsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in 386 amd64 arm; do\ + echo "Build NetBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=netbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_netbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + for ARCH in 386 amd64 arm; do\ + echo "Build OpenBSD in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=openbsd GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_openbsd_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + for ARCH in amd64; do\ + echo "Build Solaris in ARCH: $${ARCH}"; \ + CGO_ENABLED=0 GOOS=solaris GOARCH="$${ARCH}" go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; \ + cd builds; \ + shasum -a 256 securosys-hsm >> securosys-hsm_SHA256SUM; \ + zip -9 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; \ + shasum -a 256 ${ARTIFACT_NAME}_solaris_$${ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; \ + cd ..; \ + rm builds/securosys-hsm; \ + rm builds/securosys-hsm_SHA256SUM; \ + done; + + make release-alpine3 + echo "Finished!"; + +release-alpine3: + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-amd64 + make clean-docker-builder IMAGE=amd64/golang + docker compose -f docker-builder/alpine3/docker-compose-alpine3.yml run -e ARTIFACT_NAME=${ARTIFACT_NAME} golang-builder-alpine3-i386 + make clean-docker-builder IMAGE=i386/golang + +clean-docker-builder: + @if [ "$$(docker images | grep '$(IMAGE)')" != "" ]; then \ + docker rmi -f $$(docker images | grep '$(IMAGE)' | awk '{ print $$3}') 2> /dev/null || true ; \ + fi; + docker volume prune -f + docker container prune -f + docker network prune -f + +run-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml up --build -d +clean-docker-test-container: + docker compose -f ./integrationTests/docker/docker-compose.yml down --remove-orphans --rmi all + docker volume prune -f + docker container prune -f +integration-tests: + rm -fr integrationTests/docker/plugins/securosys-hsm + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -o integrationTests/docker/plugins/securosys-hsm cmd/securosys-hsm/main.go + make run-docker-test-container + + sleep 5 + go install github.com/jstemmer/go-junit-report/v2@latest + cd integrationTests/tests && go test -count=1 -tags="unit integration" -v -timeout 60m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}integration_junit_report.xml -set-exit-code + + + +build: + CGO_ENABLED=0 go build -o vault/plugins/securosys-hsm cmd/securosys-hsm/main.go + +start: + ./vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + +enable: + ./vault secrets enable securosys-hsm + +clean: + rm -f ./vault/plugins/securosys-hsm + +fmt: + go fmt $$(go list ./...) + +test: + go install github.com/jstemmer/go-junit-report/v2@latest + cd tests && go test -count=1 -tags="unit integration" -v -timeout 30m 2>&1 ./... | ${GOPATH}/bin/go-junit-report -iocopy -out ${TEST_RESULT_PATH}junit_report.xml -set-exit-code + +.PHONY: build clean fmt start enable diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4828e0e --- /dev/null +++ b/Readme.md @@ -0,0 +1,1145 @@ +# Securosys Secrets Engine for HashiCorp Vault +This plugin implements a platform-agnostic REST-based HSM interface with zero library installation, while eliminating connectivity hurdles by using secure web connections (TLS). This facilitates the use and deployment in clustered and multi-cloud environments. Moreover, all Securosys HSM innovations like hardware enforced multi-authorization and high-performance encryption (ECIES, AES-GCM) are at one's disposal, for Vault Enterprise and Community Edition. + - Manage keys securely stored on the HSM + - Perform cryptographic operations on the HSM + - Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), or hardware-enforced multi-authorization workflows for compliance, signature services, or blockchain transactions. + +This plugin is actively maintained by Securosys SA. + +## Table of Contents + +- [Glossary](#glossary) +- [How to build](#how-to-build) + - [Using pre-built releases](#using-pre-built-releases) + - [Build from sources](#build-from-sources) +- [How to run](#how-to-run) + - [Register the plugin](#register-the-plugin) + - [Upgrade the plugin](#upgrade-the-plugin) + - [How to enable the plugin](#how-to-enable-the-plugin) + - [Configure the plugin](#configure-the-plugin) + - [Manage Keys](#manage-keys) + - [Cryptographic Operations](#cryptographic-operations) + - [Requests](#requests) +- [Additional command options](#additional-command-options) +- [Help](#help) +- [Test Suite](#test-suite) + - [Preparing](#preparing) + - [Running tests](#running-tests) +- [Integrations](#integrations) + - [MariaDB](#mariadb) + - [Example usage](#mariadb-usage-example) +- [Appendix](#appendix) + - [Frequently Asked Questions](#frequently-asked-questions) + - [Key arguments](#key-arguments) + - [Full Policy JSON example](#full-policy-json-example) +- [Getting Support](#getting-support) +- [License](#license) + +--- +## Glossary +| Term| Description | +|:----------|:-------------| +| CloudsHSM | HSM as a service, operated by Securosys| +| HSM| Hardware Security Module | +| JSON | JavaScript Object Notation object | +| JWT | JSON Web Token, used to authenticate and authorize users in web applications and APIs | +| SKA | Smart Key Attributes, attributes adding rules to individual keys | +| TSB | Transaction Security Broker, providing the REST interface | +| XML | Extensible Markup Language, defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Format used for HSM key attestation. | + + +## How to build +### Using pre-built releases +You can find pre-built releases of the plugin on the Securosys JFrog artifactory. Download the latest binary file corresponding to your target OS. + +Further documentation and credentials are available via the [Securosys Support Portal](https://support.securosys.com/external/knowledge-base/article/191) or the Securosys [web-site](https://www.securosys.com/en/hashicorp-vault). + +### Build from sources + +>**Prerequisites:** Install Golang 1.16+ ([download](https://go.dev/dl/)) + +1. Run `go mod init`. + +1. Build the secrets engine as plugin using Go. + ```shell + $ CGO_ENABLED=0 go build -o vault/plugins/securosys_hsm cmd/securosys_hsm/main.go + ``` + +1. Find the binary in `vault/plugins/`. + ```shell + $ ls vault/plugins/ + ``` + +1. Run a Vault server in `dev` mode to register and try out the plugin. + ```shell + $ vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins + ``` +1. Build and test in `dev` mode. + ```shell + $ make + ``` +1. Or to build `production` plugin with the same `architecture` and `os` on used machine + + ```shell + $ make build + ``` +1. To build `production` version of this plugin, then use the command + ```shell + $ make release VERSION="1.0" #builds the plugin for the same architecture as the current machine + ``` + ```shell + $ make release VERSION="1.0" OS="win" ARCH="i386" #builds the defined plugin version + ``` +1. To build `production` for all versions of this plugin, then use the command + ```shell + $ make release-all VERSION="1.0" #builds all available versions of the plugin + ``` + This command will build `production` versions for the following architectures and operating systems + | OS | Arch | + |----------|:-------------:| + | Darwin | amd64 | + | Darwin | arm64 | + | Windows | 386 | + | Windows | amd64 | + | Linux | 386 | + | Linux | amd64 | + | Linux | arm | + | Linux | arm64 | + | FreeBSD | 386 | + | FreeBSD | amd64 | + | FreeBSD | arm | + | NetBSD | 386 | + | NetBSD | amd64 | + | NetBSD | arm | + | OpenBSD | 386 | + | OpenBSD | amd64 | + | OpenBSD | arm | + | Solaris | amd64 | + + All these builds will be zipped, calculated and stored inside the build folder of this project. + + +## How to run +### Register the plugin +In production mode the plugin has to be registered manually. +Add the following parameter in the configuration file `config.hcl` +- `plugin_directory` - must contain the absolute path to the directory where the plugins are stored + +Command to register the plugin +```shell +$ vault plugin register -sha256={binary_checksum} secret securosys-hsm +``` +### Upgrade the plugin +To upgrade a binary of an existing working plugin, follow the steps below: +1) Copy the new plugin binary to the plugin_directory. +1) Register a new version of the plugin. + ```shell + $ vault plugin register -sha256={binary_checksum} -version={new-version} secret securosys-hsm + ``` +1) Tune the existing mount to reconfigure it to use the newly registered version. + ```shell + $ vault secrets tune -plugin-version={new-version} securosys-hsm + ``` +1) Reload the plugin + ```shell + $ vault plugin reload -plugin securosys-hsm + ``` + +### How to enable the plugin +After building the plugin, before running it on test server, it must be enabled with the following command: +```shell +$ vault secrets enable securosys-hsm +``` +The result should be +```shell +$ Success! Enabled the securosys-hsm secrets engine at: securosys-hsm/ +``` +--- +### Configure the plugin +Configure the plugin for accessing the Securosys Primus HSM or CloudsHSM. + +Required attributes: +- `auth` - Attribute defines the authorization type to TSB. Values for this attribute can be `TOKEN`, `CERT` or `NONE` +- `restapi` - REST API URL to access the REST/TSB endpoint (available from your Security Officer or CloudsHSM service provider) + +Define additional attributes based on the selected authorization type `auth`: +1. `TOKEN` + Add the attribute `bearertoken` with the JWT token +1. `CERT` + Setup `certpath` with local PATH to the certificate and `keypath` with local PATH to the key. +1. `NONE` + No additional attributes required. + +Command to write the configuration to the plugin +```shell +$ vault write securosys-hsm/config {config_attributes} +``` +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode '{config_attribute_key}={config_attribute_value}' \ +``` +**Example for disabled authorization**: +```shell +$ vault write securosys-hsm/config +auth="NONE" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=NONE' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for JWT token authorization**: +```shell +$ vault write securosys-hsm/config +auth="TOKEN" +bearertoken="jwt token string" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=TOKEN' \ +--data-urlencode 'bearertoken=jwt token string' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` +**Example for Certificate authorization**: +```shell +$ vault write securosys-hsm/config +auth="CERT" +certpath="local_absolute_path_to_certificate.pem" +keypath="local_absolute_path_to_private.key" +restapi="https://primusdev.cloudshsm.com" +``` + +```shell +curl --location --request PUT '/v1/securosys-hsm/config' \ +--header 'X-Vault-Token: ' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'auth=CERT' \ +--data-urlencode 'certpath=local_absolute_path_to_certificate.pem' \ +--data-urlencode 'keypath=local_absolute_path_to_private.pem' \ +--data-urlencode 'restapi=https://primusdev.cloudshsm.com' +``` + + + +> **Note:** On any changes of the configuration, the plugin will try to reach out the defined TSB using the provided configuration. If the connection was successful, the plugin will write/overwrite the configuration, otherwise the previous configuration remains unchanged. +--- + +### Manage Keys +The plugin allows to create, modify, and manage keys on the Securosys Primus HSM or CloudsHSM by the following command sets: + +1) **list** - List all keys stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys + ``` + or for more a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` +1) **list key versions** - List all key versions stored in the **Secrets Engine** + ```shell + $ vault list securosys-hsm/keys/{key-name} + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/keys/{key-name} + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/keys' \ + --header 'X-Vault-Token: ' + ``` + +1) **read** - Read stored key info like **key label**, **policy** or **public key** + ```shell + $ vault read securosys-hsm/keys/{key-name} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + + Result of this command will be + ``` + Key Value + --- --- + algorithm {key-type} //For example: RSA, AES etc. + attributes {key-attributes} + key_size {key-size} + keyLabel {key-label-hsm} + policy {policy} //If exists + public_key {public-key-from-hsm} //If exists. Only in asymetric key + curveOid {cureveoid} //If exists. Only in EC or ED algorithms + ... + ``` + +1) **write** - Create or update a key on the **HSM** and store the reference in **Secrets Engine** + Available key types: + - **aes** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **bls** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **policy** and **password** + + - **camellia** + > *Required:* **keyLabel**, **attributes** and **keySize**[128,192,256] + > *Optionally:* **password** + + - **chacha20** + > *Required:* **keyLabel** and **attributes** + > *Optionally:* **password** + + - **dsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[512,1024,2048] + > *Optionally:* **policy** and **password** + + - **ec** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **ed** + > *Required:* **keyLabel**, **attributes** and **curveOid** + > *Optionally:* **policy** and **password** + + - **rsa** + > *Required:* **keyLabel**, **attributes** and **keySize**[1024,2048,3072,4096] + > *Optionally:* **policy** and **password** + + - **tdea** + > *Required:* **keyLabel**, **attributes** + > *Optionally:* **password** + + > **NOTE:** All fields are described in **Appendix: Key Arguments** + + > **IMPORTANT:** All keys created via Secrets Engine, have by default set the key attributes [destroyable] and [modifiable]. These attributes can be changed or extended by defining them in the `attributes` argument. + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' + ``` + + Or here an example creating a key with attached simple approval policy: + + ```shell + $ vault write securosys-hsm/keys/{key-type}/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + simplePolicy=-</v1/securosys-hsm/keys/{key-type}/{key-name}' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-hsm}' \ + --data-urlencode 'keySize={key-size}' \ + --data-urlencode 'attributes={ + #{key-attriute}:{true/false} + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": true, + "alwaysSensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }' \ + --data-urlencode 'simplePolicy={ + #{name}:{public_key} + "NameOfApprover": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBohRHhXXjQMNlxWMmCX0fxbpcMyu3bwBerkfeTl8QoOZbDV003t1n9drCuGOJJP16sZRBkYa5C7QkFCyb10Lbp1sp8jqWVu5PQy9qEaLl4y2BW+AOs0pURv1nlyo+gFgJD6lX0QmtZDjaD98C/wC5RVXipr4nJmT5XvwCPmgz9TpgVgFMwrflPJK9mHgYKwvmPODLYSLbohkj4TWKAoL417URhPazNWJBC7fKRui3EA7a8yzuzOSVgGxjY3aeqitmZyCTJtWa2U2/UwLZRT2ISwXv0zvsBhRSbXXcFdCApgKiy9uL1tPq40DnT8cesZzKd8hDYJ5S34wwmSZKbtGwIDAQAB" + }' + ``` + + Where `simplePolicy` has to be a **JSON** object in which **Key** is the name of the approval (or the approver) and **Value** has to be a valid **RSA public key** (without the "-- Begin..." and "-- End..." lines nor line breaks). + + The result of these commands will show information about the created key. + + > **NOTE:** Full SKA policy **json** can be provided by using the **policy** attribute in place of **simplePolicy**. As a policy json statement can be very large it might be difficult to edit it on command line. In such case it is recommended to attach a file with the json, using the attribute **"policy=@file.json"**. An example of the policy json file can be found in **Appendix: Full Policy JSON Example** + +1) **register** - Register an existing key stored on the HSM to Secrets Engine + ```shell + $ vault write securosys-hsm/keys/{key-name}/register keyLabel={label-of-key-on-hsm} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/register' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' + ``` + > **NOTE:** This key will be registered in Secrets Engine with the name **{key-name}** + +1) **create key by type name** - Create a key using key types compatible with HashiCorp Key Management. (https://developer.hashicorp.com/vault/api-docs/secret/key-management) + + **Available key types:** + | Key Type | Description | + |----------|-------------| + | aes256-gcm96 | AES-GCM with a 256-bit AES key and a 96-bit nonce (**symmetric**) | + | rsa-2048 | RSA with bit size of 2048 (**asymmetric**) | + | rsa-3072 | RSA with bit size of 3072 (**asymmetric**) | + | rsa-4096 | RSA with bit size of 4096 (**asymmetric**) | + | ecdsa-p256 | ECDSA using the P-256 elliptic curve (**asymmetric**) | + | ecdsa-p384 | ECDSA using the P-384 elliptic curve (**asymmetric**) | + | ecdsa-p521 | ECDSA using the P-521 elliptic curve (**asymmetric**) | + + ```shell + $ vault write securosys-hsm/keys/type/{key-type-name}/{key-name} keyLabel={label-of-key-on-hsm} + algorithm={key-algorithm} + attributes={key-attributes} + password={password} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/type/{key-type-name}/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'password={password}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be generated in Secrets Engine with the name **{key-name}** + +1) **import** - Import a new key into the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/import + keyLabel={label-of-key-on-hsm} + privateKey={private-key-base64} + publicKey={public-key-base64} + secretKey={secret-key-base64} + certificate={certificate-base64} + algorithm={key-algorithm} + attributes={key-attributes} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/import' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={label-of-key-on-hsm}' \ + --data-urlencode 'privateKey={private-key-base64}' \ + --data-urlencode 'publicKey={public-key-base64}' \ + --data-urlencode 'secretKey={secret-key-base64}' \ + --data-urlencode 'certificate={certificate-base64}' \ + --data-urlencode 'algorithm={key-algorithm}' \ + --data-urlencode 'attributes={key-attributes}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' + ``` + > **NOTE:** This key will be labeled in Secrets Engine with **{key-name}** + +1) **export** - Export public_key, private_key, or secret from a key stored on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/export [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/export' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + + +1) **modify** - Modify the SKA policy of a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/modify + [simplePolicy={policy} | policy={full-policy} | policy=@policy-file.json] + [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/modify' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **update-password** - Modify the password of a key on the HSM + ```shell + $ vault write securosys-hsm/keys/{key-name}/update-password password={current-password} newPassword="{new-password}" + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/update-password' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={current-password}' \ + --data-urlencode 'newPassword={new-password}' \ + ``` + +1) **rotate** - Rotate a key. A new key will be generated on the HSM with the same base name as the original key with an incremented version tag at the end of the original key name (_v2, _v3, ...). The previous key will remain on the HSM. + + ```shell + $ vault write securosys-hsm/keys/{key-name}/rotate + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/rotate' \ + --header 'X-Vault-Token: ' \ + --header 'Content-Type: application/x-www-form-urlencoded' + ``` + > **NOTE:** Decrypt, verify, unwrap etc. is still possible by providing the parameter **keyVersion** in the request. All other operations like encrypt, sign, wrap, block, unblock, password etc. will always use the last key version. + +1) **block** - Block a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/block [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/block' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **unblock** - Unblock a key stored on the HSM +In case the key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + ```shell + $ vault write securosys-hsm/keys/{key-name}/unblock [password={password-for-a-key}] + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/keys/{key-name}/unblock' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'password={password-for-a-key}' + ``` + > **NOTE:** Omit the **password** parameter in case no password is set. + +1) **delete** - Remove a key from the **HSM** and **Secrets Engine** + ```shell + $ vault delete securosys-hsm/keys/{key-name} [removeFromHSM=true] + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/keys/{key-name}' \ + --header 'X-Vault-Token: ' + ``` + > **NOTE:** This operation removes the key only from the **Secrets Engine**. It does not remove the key from the **HSM**. To remove all key versions from the HSM as well, then add the property **removeFromHSM** with **_true_** value. + +1) **xml** - Fetch a key attestation from the HSM in XML format, signed with the HSMs attestation key. + ```shell + $ vault read securosys-hsm/keys/{key-name}/xml + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/keys/{key-name}/xml' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + ``` + + +--- +### Cryptographic Operations +Below are the cryptographic operations that can be done using keys on the HSM. + +1) **Encrypt** - Encrypt a payload + + ```shell + $ vault write securosys-hsm/operation/encrypt/{key-name} + payload={base64-encoded-string} + password={password-of-the-key} + cipherAlgorithm={cipher-algorithm} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/encrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'payload={base64-encoded-string}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Decrypt** - Decrypt an encrypted payload +In case the referenced key has a policy attached, then a request-id is returned indicating the required approvals to collect. See section [Requests](#requests). + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/decrypt/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/decrypt/{key-name} + password={password-for-a-key} + keyVersion={key-version} + encryptedPayload={base64-encoded-string} + cipherAlgorithm={cipher-algorithm} + initializationVector={initialization-vector} + tagLength={tag-length} + additionalAuthenticationData={additional-authentication-data} + ``` + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/decrypt/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'encryptedPayload={base64-encoded-string}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'initializationVector={initialization-vector}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' + ``` + +1) **Sign** - Sign a payload +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to be collected. See section [Requests](#requests) + + ```shell + $ vault write securosys-hsm/operation/sign/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + payloadType={payload-type} + metaData={meta-data-base64} + metaDataSignature={meta-data-signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/sign/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'payloadType={payload-type}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'metaData={meta-data-base64}' \ + --data-urlencode 'metaDataSignature={meta-data-signature}' + ``` + +1) **Verify** - Verify the signature of a signed payload + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/verify/{key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + ```shell + $ vault write securosys-hsm/operation/verify/{key-name} + password={password-for-the-key} + signatureAlgorithm={algorithm} + payload={payload-base64} + signature={signature} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/verify/{key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'signatureAlgorithm={algorithm}' \ + --data-urlencode 'payload={payload-base64}' \ + --data-urlencode 'password={password-for-a-key}' \ + --data-urlencode 'signature={meta-data-signature}' + ``` + +1) **Wrap** - Wrap a key with another (wrapper) key + + ```shell + $ vault write securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name} + keyToBeWrappedPassword={password-for-first-key} + wrapKeyPassword={password-for-second-key} + wrapMethod={wrap-method} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/wrap/{key-to-be-wrapped}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyToBeWrappedPassword={password-for-first-key}' \ + --data-urlencode 'wrapKeyPassword={password-for-second-key}' \ + --data-urlencode 'wrapMethod={wrap-method}' + ``` + +1) **UnWrap** - Unwrap a key using a wrapper key +In case the referenced key has a policy attached, then a request-id is returned, indicating the required approvals to collect. See section [Requests](#requests). + + > **Note:** The **keyVersion** has to be provided in this request, either by adding it in the url (e.g. `securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}/{key-version}`), or by passing it as parameter (e.g.`keyVersion={key-version}`). + + ```shell + $ vault write securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name} + keyLabel={key-label-for-new-key} + keyVersion={key-version} + wrappedKey={wrapped-key-base64-encoded} + password={password-for-wrap-key} + wrapMethod={wrap-method} + simplePolicy={policy} or policy={full-policy} or policy=@policy-file.json + attributes={attributes} + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/operation/unwrap/{new-unwrapped-key-name}/{wrap-key-name}' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel={key-label-for-new-key}' \ + --data-urlencode 'keyVersion={key-version}' \ + --data-urlencode 'wrappedKey={wrapped-key-base64-encoded}' \ + --data-urlencode 'wrapMethod={wrap-method}' \ + --data-urlencode 'simplePolicy={policy}' or --data-urlencode 'policy={full-policy}' \ + --data-urlencode 'password={password-for-wrap-key}' + --data-urlencode 'attributes={attributes}' \ + ``` + + +--- +### Requests +In case a key has an SKA policy attached, a request object is returned instead of an instant result response, indicating the required approvals to be collected to process this request. + +For example: + +```shell +Key Value +--- ----- +approvedBy map[] +executionTime n/a +id a0d1dc5c-3c0a-415f-a184-6eaffcb9fd07 +notYetApprovedBy map[NameOfApprover:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB] +rejectedBy map[] +request map[key:custom_rsa3 keyLabel:CUSTOM_RSA_4] +result n/a +status PENDING +type UnBlock +... +etc. +``` + +To handle such requests there are the following additional commands: +1) **list** - List all requests initialized in **Secrets Engine** + ```shell + $ vault list securosys-hsm/requests + ``` + or for a more detailed list + ```shell + $ vault list -detailed securosys-hsm/requests + ``` + + ```shell + curl --location --request LIST '/v1/securosys-hsm/requests' \ + --header 'X-Vault-Token: ' + ``` +1) **read** - Show detailed request information + + ```shell + $ vault read securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request GET '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +1) **delete** - Remove a request from **Secrets Engine** and **HSM** + ```shell + $ vault delete securosys-hsm/requests/{id} + ``` + ```shell + curl --location --request DELETE '/v1/securosys-hsm/requests/{id}' \ + --header 'X-Vault-Token: ' + ``` + +--- +### Additional Command Options +All Securosys Secrets Engine commands have the additional options: +1) **-field** (string: "") - Print only the field with the given name. Specifying this option will take precedence over other formatting directives. The result will not have a trailing newline making it ideal for piping to other processes. +1) **-format** (string: "table") - Print the output in the given format. Valid formats are "table", "json", "yaml", or "raw". This can also be specified via the VAULT_FORMAT environment variable. + +--- +### Help +The command **path-help** will print help information of a specific path +```shell +$ vault path-help {path} +``` + +## Test Suite +This plugin contains prepared tests written in Golang, which can be used to test changes or all features with the used Securosys Transaction Security Broker (TSB) instance. + +### Preparing +First adapt the test configuration file `additional_test_config.go` +```go +var configParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_ADDRESS", + "auth": "TOKEN", + "bearertoken": "BEARER_TOKEN", +} +``` +Provide all necessary information in the test configuration file to gain access to the REST/TSB instance of your HSM. See [Configuration](#configure-the-plugin) section. + +### Running tests +To run all tests execute the following command in a terminal +```shell +$ go test -timeout 30m -run ^(TestOperationsEncrypt|TestOperationsSign|TestOperationsWrap|TestConfig|TestAESKey|TestBLSKey|TestCHACHA20Key|TestCamelliaKey|TestECKey|TestEDKey|TestIMPORTKey|TestRSAKey|TestTDEAKey|TestDSAKey|TestOperationsDecrypt|TestOperationsVerify|TestOperationsUnWrap|TestRequests|TestRotateKeys|TestCreateKeyUsingTypeName)$ secretengine +``` +Or run each test separately: +| Test | Description | +|:----------|:-------------| +| TestConfig | Tests write and read configuration of the plugin | +| TestAESKey | Tests connection, create, read, and delete an **AES** key | +| TestBLSKey | Tests connection, create, read, and delete a **BLS** key | +| TestCamelliaKey | Tests connection, create, read, and delete a **Camellia** key | +| TestCHACHA20Key | Tests connection, create, read, and delete a **ChaCha20** key | +| TestDSAKey | Tests connection, create, read, and delete a **DSA** key | +| TestECKey | Tests connection, create, read, and delete an **EC** key | +| TestEDKey | Tests connection, create, read, and delete an **ED** key | +| TestIMPORTKey | Tests connection, import, read, and delete an **Imported AES** key | +| TestRSAKey | Tests connection, create, read, and delete an **RSA** key | +| TestTDEAKey | Tests connection, create, read, and delete a **TDEA** key | +| TestKeys | Tests connection and all key operations (**modify**, **block**, **unblock**, **list**, **register**) | +| TestOperationsDecrypt | Tests connection and synchronous decrypt operations for all types of keys| +| TestOperationsEncrypt | Tests connection and encrypt operations for all types of keys | +| TestOperationsSign | Tests connection and synchronous sign operations for all types of keys | +| TestOperationsUnWrap | Tests connection and synchronous unwrap operations for all types of keys | +| TestOperationsVerify | Tests connection and verify operations for all types of keys | +| TestOperationsWrap | Tests connection and wrap operations for all types of keys | +| TestRequests | Tests connection and all asynchronous operations (with policy) for all types of keys | +| TestRotateKeys | Tests key rotation option for all type of keys | +| TestCreateKeyUsingTypeName | Tests key creation based on types supported by Hashicorp Vault Key Management| + +## Integrations +### MariaDB +Encryption on MariaDB can be enabled using existing plugin [Hashicorp Key Management Plugin](https://mariadb.com/kb/en/hashicorp-key-management-plugin/) +This integration stores generated secret in Secrets engine, encrypted by provided key. +**Supported Key Types**/**Algorithm** combinations: +| Key Type | Algorithm | +|----------|:-------------:| +| **RSA** |RSA_PADDING_OAEP_WITH_SHA512
RSA
RSA_PADDING_OAEP_WITH_SHA224
RSA_PADDING_OAEP_WITH_SHA256
RSA_PADDING_OAEP_WITH_SHA1
RSA_PADDING_OAEP
RSA_PADDING_OAEP_WITH_SHA384
RSA_NO_PADDING| +|**AES**|AES_GCM
AES_CTR
AES_ECB
AES_CBC_NO_PADDING
AES | +| **CHACHA20** | CHACHA20
CHACHA20_AEAD| +| **CAMELLIA** | CAMELLIA
CAMELLIA_CBC_NO_PADDING
CAMELLIA_ECB | +|**TDEA**| TDEA_CBC
TDEA_ECB
TDEA_CBC_NO_PADDING | + +>**Note** - Plugin supports **asynchronous decrypt operation** using key type **RSA** with **policy** with setup **ruleUse**. Using the key with policy will **stop** the decrypt operation and **wait for approvals** to be collected. + +There are a **serval steps** that is needed to be done before setup encryption on MariaDB +1) [Create / Register key](#manage-keys) into **Secrets Engine** +1) Generate new **secret** and encrypt it using stored key + ```shell + $ vault write securosys-hsm/integrations/mariadb/{secret-name} + keyName={key-name-from-secret-engine} + cipherAlgorithm={cipher-algorithm} + [additionalAuthenticationData={additional-authentication-data}] + [tagLength={tag-length}] + [password={password-for-a-key}] + ``` + + ```shell + curl --location --request PUT '/v1/securosys-hsm/integrations/mariadb/{secret-name} ' \ + --header 'X-Vault-Token: ' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName={key-name-from-secret-engine}' \ + --data-urlencode 'cipherAlgorithm={cipher-algorithm}' \ + --data-urlencode 'tagLength={tag-length}' \ + --data-urlencode 'additionalAuthenticationData={additional-authentication-data}' \ + --data-urlencode 'password={password-for-a-key}' + ``` + >**Note** - Every request on this endpoint using same **key name** and **secret name** will **rotate secret** +1) The last step is add this configuration to **my.cfg** + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" + loose-hashicorp-key-management-token="{vault_access_token}" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + >**Note** - In **loose-hashicorp-key-management-vault-url** url need to ends with **&version=**. Plugin from **MariaDB** automatically add to end of url **number of secret version** +#### MariaDB usage example +This example using default configuration for **Hashicorp Vault dev server**. +| Data | Value | +|----------|:-------------:| +| **vault address** | https://localhost:8200 | +| **vault access token** | root | +1) **Create key** *MariaDBEncryptionKey* with key size *4096* with attributes at last "decrypt" equals *true* on HSM and store it as *mariadb_encryption_key* on **Secrets engine** + ```shell + $ vault write securosys-hsm/keys/rsa/mariadb_encryption_key + keyLabel="MariaDBEncryptionKey" + keySize=4096 + attributes='{"decrypt": true,"sign": false,"unwrap": false,"derive": true,"sensitive": true,"extractable": false,"modifiable": false,"copyable": false,"destroyable": true}' + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/keys/rsa/mariadb_encryption_key' \ + --header 'X-Vault-Token: root' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyLabel=MariaDBEncryptionKey' \ + --data-urlencode 'keySize=4096' \ + --data-urlencode 'attributes={ + "decrypt": true, + "sign": false, + "unwrap": false, + "derive": true, + "sensitive": true, + "extractable": false, + "neverExtractable": true, + "modifiable": false, + "copyable": false, + "destroyable": true + }' + ``` +1) Generate new **secret** called *mariadb_secret* and **encrypt it** using cipher algorithm *RSA* and stored key *mariadb_encryption_key* in **Secrets engine** + ```shell + $ vault write securosys-hsm/integrations/mariadb/mariadb_secret + keyName=mariadb_encryption_key + cipherAlgorithm=RSA + ``` + or + ```shell + curl --location --request PUT 'https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret ' \ + --header 'X-Vault-Token: root' + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'keyName=mariadb_encryption_key' \ + --data-urlencode 'cipherAlgorithm=RSA' + ``` +3. Configure **MariaDB plugin** "Hashicorp Key Management" in database configuration in **my.cnf** + + ```ini + [mariadb] + plugin-load-add=hashicorp_key_management.so + loose-hashicorp-key-management + loose-hashicorp-key-management-vault-url="https://localhost:8200/v1/securosys-hsm/integrations/mariadb/mariadb_secret/?key_name=mariadb_encryption_key&cipher_algorithm=RSA&version=" + loose-hashicorp-key-management-token="root" + loose-hashicorp-key-management-check-kv-version="off" + #max timeout is 86400 seconds + loose-hashicorp-key-management-timeout=3000 + loose-hashicorp-key-management-retries=0 + loose-hashicorp-key-management-use-cache-on-timeout="on" + loose-hashicorp-key-management-caching-enabled="on" + #1 year in miliseconds + loose-hashicorp-key-management-cache-timeout=31556952000 + #1 year in miliseconds + loose-hashicorp-key-management-cache-version-timeout=31556952000 + + #Example of innodb config + innodb_encrypt_tables = ON + innodb_encrypt_temporary_tables = ON + innodb_encrypt_log = ON + innodb_encryption_threads = 4 + innodb_encryption_rotate_key_age = 1 + ``` + + + +--- +## Appendix +### Frequently Asked Questions +1) > **I got the error 'no handler for route "securosys-hsm/...". route entry found, but backend is nil.'** + In case of ```no handler for route "securosys-hsm/...". route entry found, but backend is nil.``` error, try to replace the secrets engine binary and to register the new upgraded plugin. See [How to run > Upgrade plugin](#upgrade-the-plugin) + +1) > **Why I don't get a public key and policy on some key types** + Some key types are symmetric, and therefore don't have a public key nor a SKA policy. + +1) > **I have an error on unwrapping a key - status: 500, body: {"errorCode":701,"reason":"res.error.in.hsm","message":"Error unwrapping key"}** + Probably the provided key label is already in use with another key on the HSM, or the request contains a policy for a symmetric key. + +### Key Arguments + +> **keyLabel:** The created key will be stored on the HSM with this name. This parameter is **required**. + +> **attributes:** The attributes of the key that should be created. At least one cryptographic operation (**decrypt**, **sign**, **unwrap**) must be allowed (**true**). This parameter is **required**. + +**Available key attributes:** +1) **encrypt** - The key can be used to encrypt data. +1) **decrypt** - The key can be used to decrypt data. +1) **verify** - The key can be used to verify signatures. +1) **sign** - The key can be used to create signatures. +1) **wrap** - The key can be used to wrap another key. +1) **unwrap** - The key can be used to unwrap keys. +1) **derive** - The key can be derivable. **default**: *false* +1) **bip32** - Key derivation is done using BIP32. This option can only be true if the key's algorithm is EC and the derive attribute is true. **default**: *false* +1) **extractable** - The key is extractable. This option can only be true for keys without smart key attributes. **default**: *false* +1) **modifiable** - The key can be modified. **default**: *true* +1) **destroyable** - The key can be deleted. **default**: *true* +1) **sensitive** - The key is sensitive. To export a key sensitive must be false +1) **copyable** - The encrypted key is stored in an external memory. **default**: *false* + +**Structure** Allows to define the attributes as a **JSON object**. Key = Value structure. +For example: +```json +{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "modifiable": true, + "copyable": false, + "destroyable": true +} +``` +> **curveOid:** The oid of the curve used for the EC or ED algorithm. Mandatory if the chosen algorithm is set to EC or ED. Sample OID's: secp256k1=1.3.132.0.10, Ed25519=1.3.101.112, secp384r1=1.3.132.0.34, (prime256v1 / secp256r1): 1.2.840.10045.3.1.7 + +> **keySize:** The length of the key. Only applicable for AES, Camellia, RSA , DSA. + +> **policy:** Defines the SKA policy of a key. Contains the rules to use this key for signing a payload in a sign request, the rules to block and unblock this key, and the rules to modify the policy of this key. If a rule is empty the associated operation can be performed without any approvals. If the policy is empty the key does not use smart key attributes, and it is not possible to add them later. If a policy is used with the key, the key cannot be exported. +**Structure** Allows to define all required approvals as a **JSON object**. Key = Value structure. + +For example: +```json +{ + "TM": public_key_1, + "WK": public_key_2, +} +``` +### Full Policy JSON Example +```json +{ + "ruleUse": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "Token Name", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "Group Name", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "Name", + "value": "RSA_PUBLIC_KEY" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } +} +``` +## Getting Support +**Community Support for Securosys open source software:** +In our Community we welcome contributions. The Community software is open source and community supported, there is no support SLA, but a helpful best-effort Community. + + - To report a problem or suggest a new feature, use the [Issues](https://github.com/securosys-com/hcvault-plugin-secrets-engine/issues) tab. + +**Commercial Support for REST/TSB and HSM related issues:** +Securosys customers having an active support contract, open a support ticket via [Securosys Support Portal](https://support.securosys.com/external/service-catalogue/21). + +**Getting a temporary CloudsHSM developer account:** +Check-out a time limited developer account by registering [here](https://app.securosys.com) and choosing *Trial Account*. + +## License + Securosys Secrets Engine is licensed under the Apache License, please see [LICENSE](https://github.com/securosys-com/hcvault-plugin-secrets-engine/LICENSE). diff --git a/backend/backend.go b/backend/backend.go new file mode 100644 index 0000000..67cf38a --- /dev/null +++ b/backend/backend.go @@ -0,0 +1,140 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "strings" + "sync" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + client "securosys.ch/client" + helpers "securosys.ch/helpers" +) + +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend() + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// securosysBackend defines an object that +// extends the Vault backend and stores the +// target API's client. +type SecurosysBackend struct { + *framework.Backend + lock sync.RWMutex + client *client.SecurosysClient +} + +// backend defines the target API backend +// for Vault. It must include each path +// and the secrets it will store. +func Backend() *SecurosysBackend { + var b = SecurosysBackend{} + + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + PathsSpecial: &logical.Paths{ + LocalStorage: []string{}, + SealWrapStorage: []string{ + "config", + "keys/*", + }, + }, + Paths: framework.PathAppend( + pathHSM_AESKeys(&b), + pathHSM_RSAKeys(&b), + pathHSM_DSAKeys(&b), + pathHSM_ChaCha20Keys(&b), + pathHSM_CamelliaKeys(&b), + pathHSM_TDEAKeys(&b), + pathHSM_ECKeys(&b), + pathHSM_EDKeys(&b), + pathHSM_BLSKeys(&b), + pathHSM_ImportKeys(&b), + pathHSM_KeyNamesKeys(&b), + pathHSMHealth(&b), + pathHSMKeys(&b), + pathOperations(&b), + pathRequests(&b), + pathMariaDBIntegration(&b), + []*framework.Path{ + pathConfig(&b), + }, + ), + Secrets: []*framework.Secret{}, + BackendType: logical.TypeLogical, + Invalidate: b.Invalidate, + } + return &b +} + +// reset clears any client configuration for a new +// backend to be configured +func (b *SecurosysBackend) Reset() { + b.lock.Lock() + defer b.lock.Unlock() + b.client = nil +} + +// invalidate clears an existing client configuration in +// the backend +func (b *SecurosysBackend) Invalidate(ctx context.Context, key string) { + if key == "config" { + b.Reset() + } +} + +// getClient locks the backend as it configures and creates a +// a new client for the target API +func (b *SecurosysBackend) GetClient(ctx context.Context, s logical.Storage) (*client.SecurosysClient, error) { + b.lock.RLock() + unlockFunc := b.lock.RUnlock + defer func() { unlockFunc() }() + + if b.client != nil { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + config, err := getConfig(ctx, s) + if err != nil { + return nil, err + } + + if config == nil { + config = new(helpers.SecurosysConfig) + } + + b.client, err = client.NewClient(config) + if err != nil { + return nil, err + } + + return b.client, nil +} + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..d955830 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,62 @@ +module securosys.ch/backend + +replace securosys.ch/helpers => ./../helpers + +replace securosys.ch/client => ./../client + + +go 1.19 + +require ( + github.com/andreburgaud/crypt2go v1.2.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/client v0.0.0-00010101000000-000000000000 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/path_config.go b/backend/path_config.go new file mode 100644 index 0000000..13e18f4 --- /dev/null +++ b/backend/path_config.go @@ -0,0 +1,291 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// pathConfig extends the Vault API with a `/config` +// endpoint for the backend. You can choose whether +// or not certain attributes should be displayed, +// required, and named. For example, password +// is marked as sensitive and will not be output +// when you read the configuration. +func pathConfig(b *SecurosysBackend) *framework.Path { + return &framework.Path{ + Pattern: "config", + Fields: map[string]*framework.FieldSchema{ + "auth": { + Type: framework.TypeString, + Description: "Authorization Type for Securosys HSM. It can be NONE,TOKEN,CERT", + Required: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "Auth", + Sensitive: false, + }, + }, + "bearertoken": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='TOKEN'. It must contain valid Bearer Token", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "BearerToken", + Sensitive: true, + }, + }, + "certpath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to certificate", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "CertPath", + Sensitive: false, + }, + }, + "keypath": { + Type: framework.TypeString, + Description: "This parameter is needed if we set Auth='CERT'. It must contain valid local path to key", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "KeyPath", + Sensitive: false, + }, + }, + "restapi": { + Type: framework.TypeString, + Description: "This parameter must contain url address to TSB", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "RestApi", + Sensitive: false, + }, + }, + "applicationKeyPair": { + Type: framework.TypeString, + Description: "This parameter must contain ApplicationKeyPair (RSA) to sign async requests", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "ApplicationKeyPair", + Sensitive: false, + }, + }, + "apiKeys": { + Type: framework.TypeString, + Description: "This parameter must contain ApiKeys", + Required: false, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "ApiKeys", + Sensitive: false, + }, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathConfigRead, + }, + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathConfigWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathConfigDelete, + }, + }, + ExistenceCheck: b.pathConfigExistenceCheck, + HelpSynopsis: pathConfigHelpSynopsis, + HelpDescription: pathConfigHelpDescription, + } +} + +// pathConfigExistenceCheck verifies if the configuration exists. +func (b *SecurosysBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) { + out, err := req.Storage.Get(ctx, req.Path) + if err != nil { + return false, fmt.Errorf("existence check failed: %w", err) + } + + return out != nil, nil +} + +// pathConfigRead reads the configuration and outputs non-sensitive information. +func (b *SecurosysBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + return &logical.Response{ + Data: map[string]interface{}{ + "username": config.Username, + "restapi": config.RestApi, + "auth": config.Auth, + "certpath": config.CertPath, + }, + }, nil +} + +// pathConfigWrite updates the configuration for the backend +func (b *SecurosysBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := getConfig(ctx, req.Storage) + if err != nil { + return nil, err + } + + createOperation := (req.Operation == logical.CreateOperation) + + if config == nil { + if !createOperation { + return nil, errors.New("config not found during update operation") + } + config = new(helpers.SecurosysConfig) + } + if auth, ok := data.GetOk("auth"); ok { + config.Auth = auth.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing auth in configuration") + } + // if config.Auth != "TOKEN" && config.Auth != "BASIC" && config.Auth != "CERT" && config.Auth != "NONE" { + // return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,BASIC,CERT)") + // } + if config.Auth != "TOKEN" && config.Auth != "CERT" && config.Auth != "NONE" { + return nil, fmt.Errorf("auth must have one of following values (NONE,TOKEN,CERT)") + } + + if bearertoken, ok := data.GetOk("bearertoken"); ok { + config.BearerToken = bearertoken.(string) + } else if !ok && createOperation && config.Auth == "TOKEN" { + return nil, fmt.Errorf("missing bearertoken in configuration. It's required when You choose Auth='TOKEN'") + } + // if basictoken, ok := data.GetOk("basictoken"); ok { + // config.BearerToken = basictoken.(string) + // } else if !ok && createOperation && config.Auth == "BASIC" { + // if username, ok := data.GetOk("username"); ok { + // config.Username = username.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // if password, ok := data.GetOk("password"); ok { + // config.Password = password.(string) + // } + // if !ok && createOperation { + // return nil, fmt.Errorf("missing basictoken or username and password in configuration. It's required when You choose Auth='BASIC'. You can use only BasicToken, then combination of Username and Password will be ignored") + // } + // } + + if certpath, ok := data.GetOk("certpath"); ok { + config.CertPath = certpath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing certpath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.CertPath) + + if err != nil { + return nil, fmt.Errorf("Certpath in configuration is not valid. Error: %s", err.Error()) + } + } + if keypath, ok := data.GetOk("keypath"); ok { + config.KeyPath = keypath.(string) + } else if !ok && createOperation && config.Auth == "CERT" { + return nil, fmt.Errorf("missing keypath in configuration. It's required when You choose Auth='CERT'") + } + if config.Auth == "CERT" { + _, err := os.ReadFile(config.KeyPath) + + if err != nil { + return nil, fmt.Errorf("Keypath in configuration is not valid. Error: %s", err.Error()) + } + } + if restapi, ok := data.GetOk("restapi"); ok { + config.RestApi = restapi.(string) + } else if !ok && createOperation { + return nil, fmt.Errorf("missing restapi in configuration") + } + if applicationKeyPair, ok := data.GetOk("applicationKeyPair"); ok { + config.ApplicationKeyPair = applicationKeyPair.(string) + } + if apiKeys, ok := data.GetOk("apiKeys"); ok { + config.ApiKeys = apiKeys.(string) + } + + entry, err := logical.StorageEntryJSON("config", config) + if err != nil { + return nil, err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return nil, err + } + + // reset the client so the next invocation will pick up the new configuration + b.Reset() + client, err := b.GetClient(ctx, req.Storage) + body, _, err := client.CheckConnection() + if err != nil { + return nil, fmt.Errorf("Cannot make a connection. %s", err.Error()) + } + return &logical.Response{ + Data: map[string]interface{}{ + "result": "Connection successful: " + body, + }, + }, nil + +} + +// pathConfigDelete removes the configuration for the backend +func (b *SecurosysBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "config") + + if err == nil { + b.Reset() + } + + return nil, err +} + +func getConfig(ctx context.Context, s logical.Storage) (*helpers.SecurosysConfig, error) { + entry, err := s.Get(ctx, "config") + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + config := new(helpers.SecurosysConfig) + if err := entry.DecodeJSON(&config); err != nil { + return nil, fmt.Errorf("error reading root configuration: %w", err) + } + + // return the config, we are done + return config, nil +} diff --git a/backend/path_help.go b/backend/path_help.go new file mode 100644 index 0000000..8862a6e --- /dev/null +++ b/backend/path_help.go @@ -0,0 +1,483 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +const backendHelp = ` +The Securosys Secrets Engine plugin implements a platform-agnostic REST-based +HSM interface with zero library installation, while eliminating connectivity hurdles +by using secure web connections (TLS). +This facilitates the use and deployment in clustered and multi-cloud environments. +Moreover, all Securosys HSM innovations like hardware enforced multi-authorization +and high-performance encryption (ECIES, AES-GCM) are at one�s disposal, +for Vault Enterprise and Community Edition. The plugin allows to +- Manage keys securely stored on the HSM +- Perform cryptographic operations on the HSM +- Use enhanced Primus HSM features such as high-performance encryption (ECIES, AES-GCM), + or hardware-enforced multi-authorization workflows + for compliance, signature services, or blockchain transactions. + +After registering and enabling this plugin, configure access and authorization for +HSMs REST/TSB interface with the "config/" endpoint. +` + +const pathConfigHelpSynopsis = `Configure the Securosys Secrets Engine Plugin for HSM access` +const pathConfigHelpDescription = `The Securosys Secrets Engine requires configuration to access the HSM via REST(TSB). Authorization type can be token (JWT), cert (mTLS client certificate), or disabled. + Example: $ vault write securosys-hsm/config + auth={authorization-type} # Possible values (NONE,TOKEN,CERT) + restapi={rest-api-url} # REST API URL to access the REST/TSB endpoint + bearertoken={bearer-token} # If Auth=TOKEN + certpath={path-to-certificate} # If Auth=CERT + ` + +const ( + pathHealthHelpSynopsis = `Get status of connection` + pathHealthHelpDescription = `Get the status of the connection between Secrets Engin plugin and TSB. + Example: $ vault read securosys-hsm/health` +) + +const ( + pathKeyAESHelpSynopsis = `Create AES key` + pathKeyAESHelpDescription = ` + Create an AES key. Arguments required: keyLabel, keySize, attributes. Optional: password + Example: $ vault write securosys-hsm/keys/aes/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} +` +) + +const ( + pathKeyBLSHelpSynopsis = `Create BLS key` + pathKeyBLSHelpDescription = ` + Create a BLS key. Arguments required: keyLabel, keySize, attributes. Optional: password, policy, simplePolicy + Example: $ vault write securosys-hsm/keys/bls/{key-name} + keyLabel="{key-label-hsm}" + keySize={key-size} + #{key-attriute}:{true/false} + attributes='{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}' + password={password-for-the-key} + policy=@path_to_policy_file.json + #or + #JSON object (Key => Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< Approver Name, Value=>Approver Public Key) + simplePolicy=-< 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens) > 0 { + for _, value := range key.Versions[key.CurrentVersion].Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if key.Versions[key.CurrentVersion].Policy.KeyStatus != nil { + if key.Versions[key.CurrentVersion].Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + keyInfo[name] = map[string]interface{}{ + "Algorithm": key.Algorithm, + "KeySize": key.KeySize, + "KeyLabel": key.GetActiveVersion().KeyLabel, + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Version": key.CurrentVersion, + "Created": key.Created.Name, + "Updated": key.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + keys := make([]string, 0, len(entry.Versions)) + keyInfo := make(map[string]interface{}) + for key, version := range entry.Versions { + keys = append(keys, key) + if err == nil { + configuredPolicy := "no" + if len(version.Policy.RuleBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUnBlock.Tokens) > 0 { + for _, value := range version.Policy.RuleUnBlock.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleUse.Tokens) > 0 { + for _, value := range version.Policy.RuleUse.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + if len(version.Policy.RuleModify.Tokens) > 0 { + for _, value := range version.Policy.RuleModify.Tokens { + if len(value.Groups) > 0 { + configuredPolicy = "yes" + } + } + } + blocked := "no" + if version.Policy.KeyStatus != nil { + if version.Policy.KeyStatus.Blocked == true { + blocked = "yes" + } + } + isCurrentVersion := "no" + if entry.CurrentVersion == key { + isCurrentVersion = "yes" + } + keyInfo[key] = map[string]interface{}{ + "WithPolicy": configuredPolicy, + "Blocked": blocked, + "Active": isCurrentVersion, + "Version": key, + "Created": version.Created.Name, + "Updated": version.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(keys, keyInfo), nil +} + +// This function prints lists of stored keys +func (b *SecurosysBackend) pathKeyVersionRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + version, ok := d.GetOk("version") + if !ok { + return logical.ErrorResponse("missing version of key"), nil + } + + if helpers.ContainsKey(entry.Versions, version) == false { + + return logical.ErrorResponse("Version %s not exists for a key %s", version.(string), d.Get("name").(string)), nil + } + keyVersion := entry.Versions[version.(string)] + return &logical.Response{ + Data: keyVersion.ToResponseData(*entry), + }, nil +} + +// This function prints single key +func (b *SecurosysBackend) pathKeysRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Key with name %s not exists", d.Get("name").(string)) + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function prints single key XML and Signature +func (b *SecurosysBackend) pathKeysReadXML(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + return &logical.Response{ + Data: entry.ToResponseDataXML(), + }, nil +} + +// This function exports key secret, public_key, private_key outside HSM +func (b *SecurosysBackend) pathKeysExportWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("key with the name %s not exists", name.(string)), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + result, errPost := client.ExportKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errPost != nil { + return nil, errPost + } + + return &logical.Response{ + Data: result, + }, nil + +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRegisterWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry != nil { + return logical.ErrorResponse("Key with name %s already exists.", name.(string)), nil + + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Created.Aliases = entity.Aliases + keyEntry.Created.Id = entity.ID + keyEntry.Created.Name = entity.Name + keyVersion.Created.Aliases = entity.Aliases + keyVersion.Created.Id = entity.ID + keyVersion.Created.Name = entity.Name + } else { + keyEntry.Created.Id = "root" + keyEntry.Created.Name = "root" + keyEntry.Created.Aliases = nil + keyVersion.Created.Id = "root" + keyVersion.Created.Name = "root" + keyVersion.Created.Aliases = nil + } + } + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + if keylabel, ok := d.GetOk("keyLabel"); ok { + keyEntry.BaseLabel = keylabel.(string) + } else if !ok { + return nil, fmt.Errorf("missing keyLabel in key") + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + key, errGet := client.GetKey(keyEntry.BaseLabel, passwordString) + if errGet != nil { + return nil, errGet + } + if !helpers.Contains(helpers.SUPPORTED_KEY_TYPES, key.Algorithm) { + return nil, fmt.Errorf("%s algorithm is not supported!", key.Algorithm) + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.CurveOid = key.CurveOid + keyEntry.KeySize = key.KeySize + + keyVersion.Policy = key.Policy + keyVersion.PublicKey = key.PublicKey + keyVersion.KeyLabel = key.Label + keyVersion.Xml = key.Xml + keyVersion.XmlSignature = key.XmlSignature + keyVersion.AttestationKeyName = key.AttestationKeyName + keyVersion.Version = "v1" + + keyEntry.Versions = make(map[string]helpers.KeyVersion) + keyEntry.CurrentVersion = "v1" + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function register existing key in HSM into Secrets Engine +func (b *SecurosysBackend) pathKeysRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + sysView := b.System() + keyVersion := &helpers.KeyVersion{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyVersion.Updated.Aliases = entity.Aliases + keyVersion.Updated.Id = entity.ID + keyVersion.Updated.Name = entity.Name + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyVersion.Updated.Aliases = nil + keyVersion.Updated.Id = "root" + keyVersion.Updated.Name = "root" + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + currentVersion := keyEntry.CurrentVersion + currentKeyVersion := keyEntry.Versions[currentVersion] + + switch keyEntry.Algorithm { + case "BLS": + keyEntry.KeySize = 0 + case "TDEA": + keyEntry.KeySize = 0 + case "ED": + keyEntry.CurveOid = keyEntry.AlgorithmOid + } + var key string + if helpers.Contains(helpers.ASYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, ¤tKeyVersion.Policy, keyEntry.CurveOid, false) + } else { + key, err = client.CreateOrUpdateKey(keyEntry.BaseLabel+"_"+helpers.GetNewVersion(currentVersion), passwordString, keyEntry.Attributes, keyEntry.Algorithm, keyEntry.KeySize, nil, keyEntry.CurveOid, false) + } + if err != nil { + return nil, err + } + keyInfo, errGet := client.GetKey(key, passwordString) + if errGet != nil { + return nil, errGet + } + + keyEntry.CurrentVersion = helpers.GetNewVersion(currentVersion) + keyVersion.Version = helpers.GetNewVersion(currentVersion) + keyVersion.PublicKey = keyInfo.PublicKey + keyVersion.Policy = keyInfo.Policy + keyVersion.Xml = keyInfo.Xml + keyVersion.XmlSignature = keyInfo.XmlSignature + keyVersion.AttestationKeyName = keyInfo.AttestationKeyName + keyVersion.KeyLabel = keyInfo.Label + keyEntry.Versions[keyEntry.CurrentVersion] = *keyVersion + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to block key on HSM +func (b *SecurosysBackend) pathKeysBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + if len(keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.Block(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = true + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to block key on HSM. This command is only use, when key have a policy with Block Rule +func (b *SecurosysBackend) pathKeysAsyncBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, _, errEnc := client.AsyncBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, _, errReq := client.GetRequest(requestId) + + if errReq != nil { + + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Block" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to unblock key on HSM +func (b *SecurosysBackend) pathKeysUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUnBlock.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncUnBlockWrite(ctx, req, d) + } + } + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + _, errGet := client.UnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.GetActiveVersion().Policy.KeyStatus.Blocked = false + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + keyEntry.Updated.Date = time.Now() + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + return nil, nil +} + +// This function send command to unblock key on HSM. This command is only use, when key have a policy with UnBlock rule +func (b *SecurosysBackend) pathKeysAsyncUnBlockWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + keyEntry = &helpers.KeyEntry{} + } + + client, err := b.GetClient(ctx, req.Storage) + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + requestId, _, errEnc := client.AsyncUnBlock(keyEntry.GetActiveVersion().KeyLabel, passwordString, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, _, errReq := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnBlock" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to modify key policy on HSM. +func (b *SecurosysBackend) pathKeysModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if len(keyEntry.GetActiveVersion().Policy.RuleModify.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleModify.Tokens { + if len(token.Groups) > 0 { + return b.pathKeysAsyncModifyWrite(ctx, req, d) + } + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.Modify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy) + if errModify != nil { + return nil, errModify + } + key, errGet := client.GetKey(keyEntry.GetActiveVersion().KeyLabel, passwordString) + if errGet != nil { + return nil, errGet + } + keyEntry.Algorithm = key.Algorithm + keyEntry.AlgorithmOid = key.AlgorithmOid + keyEntry.CurveOid = key.CurveOid + keyEntry.Attributes = key.Attributes + keyEntry.BaseLabel = key.Label + keyEntry.KeySize = key.KeySize + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.PublicKey = key.PublicKey + entry.Policy = key.Policy + entry.Xml = key.Xml + entry.XmlSignature = key.XmlSignature + entry.AttestationKeyName = key.AttestationKeyName + entry.KeyLabel = key.Label + keyEntry.Versions[keyEntry.CurrentVersion] = entry + } + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to modify key policy on HSM. This command is only use, when key have a policy with modifyRule +func (b *SecurosysBackend) pathKeysAsyncModifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + + var hasPolicy bool = false + var policy helpers.Policy + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + policyObj, err := helpers.PrepareFullPolicy(simplePolicy.(string), true, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + policyObj, err := helpers.PrepareFullPolicy(policy.(string), false, false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PrepareFullPolicy("{}", true, false) + policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + requestId, _, errEnc := client.AsyncModify(keyEntry.GetActiveVersion().KeyLabel, passwordString, policy, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, _, errReq := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Modify" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = name.(string) + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + sysView := b.System() + + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + if entry, ok := requestEntry.Key.Versions[requestEntry.KeyVersion]; ok { + entry.Password = passwordString + } + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function send command to change/update password for key on HSM. +func (b *SecurosysBackend) pathKeysUpdatePasswordWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name, ok := d.GetOk("name") + if !ok { + return logical.ErrorResponse("missing key name"), nil + } + + keyEntry, err := b.GetKey(ctx, req.Storage, name.(string)) + if err != nil { + return nil, err + } + if keyEntry == nil { + return logical.ErrorResponse("Key with name %s not exists", name), nil + } + if helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyEntry.Algorithm) { + return logical.ErrorResponse("Operation for %s rejected. Cannot setup password on symetric keys", name), nil + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } else { + return logical.ErrorResponse("missing key password"), nil + } + newPassword, ok := d.GetOk("newPassword") + newPasswordString := "" + if ok { + newPasswordString = newPassword.(string) + } else { + return logical.ErrorResponse("missing key newPassword"), nil + } + + client, err := b.GetClient(ctx, req.Storage) + _, errModify := client.UpdateKeyPassword(keyEntry.GetActiveVersion().KeyLabel, passwordString, newPasswordString) + if errModify != nil { + return nil, errModify + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + keyEntry.Updated.Aliases = entity.Aliases + keyEntry.Updated.Id = entity.ID + keyEntry.Updated.Name = entity.Name + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } else { + keyEntry.Updated.Id = "root" + keyEntry.Updated.Name = "root" + keyEntry.Updated.Aliases = nil + if entry, ok := keyEntry.Versions[keyEntry.CurrentVersion]; ok { + entry.Updated = keyEntry.Updated + keyEntry.Versions[keyEntry.CurrentVersion] = entry + + } + } + if err := SetKey(ctx, req.Storage, name.(string), keyEntry); err != nil { + return nil, err + } + + return nil, nil +} + +// This function send command to delete key in Secrets Engine. Additionaly We can delete key on HSM as well with additional parameter +func (b *SecurosysBackend) pathKeyVersionDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + if !helpers.ContainsKey(entry.Versions, d.Get("version").(string)) { + return nil, fmt.Errorf("error deleting securosys key: key version %s not exists", d.Get("version").(string)) + } + if entry.CurrentVersion == d.Get("version").(string) { + return nil, fmt.Errorf("error deleting securosys key: cannot remove current active key") + } + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + errReq := client.RemoveKeyVersion(entry.Versions, d.Get("version").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + delete(entry.Versions, d.Get("version").(string)) + + if err := SetKey(ctx, req.Storage, d.Get("name").(string), entry); err != nil { + return nil, err + } + + return nil, nil +} +func (b *SecurosysBackend) pathKeysDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, errGet := b.GetKey(ctx, req.Storage, d.Get("name").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errGet) + } + if entry == nil { + return nil, fmt.Errorf("error deleting securosys key: key with name %s not exists", d.Get("name").(string)) + + } + removeFromHSM := d.Get("removeFromHSM") + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errClient) + + } + if removeFromHSM.(bool) { + errReq := client.RemoveKeyAllVersions(*entry) + if errReq != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", errReq) + + } + } + + err := req.Storage.Delete(ctx, "keys/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +// This function helps with saving key in Secrets Engine +func SetKey(ctx context.Context, s logical.Storage, name string, keyEntry *helpers.KeyEntry) error { + entry, err := logical.StorageEntryJSON("keys/"+name, keyEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for key") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetKey(ctx context.Context, s logical.Storage, name string) (*helpers.KeyEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "keys/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var key helpers.KeyEntry + + if err := entry.DecodeJSON(&key); err != nil { + return nil, err + } + return &key, nil +} diff --git a/backend/path_hsm_operations.go b/backend/path_hsm_operations.go new file mode 100644 index 0000000..ea8e6e6 --- /dev/null +++ b/backend/path_hsm_operations.go @@ -0,0 +1,2421 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for making operation using key like: encrypt, decrypt, sign, verify etc. +func pathOperations(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "operation/wrap/" + framework.GenericNameRegex("keyToBeWrapped") + "/" + framework.GenericNameRegex("wrappedKeyName"), + Fields: map[string]*framework.FieldSchema{ + "keyToBeWrapped": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that shall be wrapped", + Required: true, + }, + "wrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key with which the key shall be wrapped.", + Required: true, + }, + "keyToBeWrappedPassword": { + Type: framework.TypeString, + Description: "Password of the key that shall be wrapped.", + Required: false, + }, + "wrapKeyPassword": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationWrap, + logical.CreateOperation: b.pathOperationWrap, + }, + HelpSynopsis: pathOperationsWrapHelpSyn, + HelpDescription: pathOperationsWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/unwrap/" + framework.GenericNameRegex("unwrappedKeyName") + "/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that used to wrap", + Required: true, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in wrap request", + Required: true, + }, + "unwrappedKeyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key that Wee want to store", + Required: true, + }, + "keyLabel": { + Type: framework.TypeString, + Description: "Label for a new unwrapped key on HSM", + Required: true, + }, + + "wrappedKey": { + Type: framework.TypeString, + Description: "The key (base64 encoded) that shall be unwrapped", + Required: false, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the wrap key.", + Required: false, + }, + "wrapMethod": { + Type: framework.TypeString, + Description: "The wrap method to be used. The chosen method has to be compatible with the types of the referenced keys", + Required: true, + }, + "policy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. For this attribute You have to provide full JSON policy. Only for synchronous unwrap!", + Required: false, + }, + + "simplePolicy": { + Type: framework.TypeString, + Description: "Key policy for Securosys HSM. JSON object format. Example {'name':'public_key', 'name2':'public_key2'}", + Required: false, + }, + "attributes": { + Type: framework.TypeString, + Description: "The attributes of the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). JSON object format. Example {'attribute1':false, 'attribute2':true}. You can setup encrypt, decrypt, verify, sign, wrap, unwrap, derive, bip32, extractable, modifiable, destroyable, sensitive and copyable", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationUnWrap, + logical.CreateOperation: b.pathOperationUnWrap, + }, + HelpSynopsis: pathOperationsUnWrapHelpSyn, + HelpDescription: pathOperationsUnWrapHelpDesc, + }, + { + Pattern: "operation/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. The chosen algorithm has to be compatible with the type of the key referenced by the signKeyName param.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload that shall be signed. It has to be base64 encoded", + Required: true, + }, + "payloadType": { + Type: framework.TypeString, + Description: "The type of the payload.", + Required: false, + Default: "UNSPECIFIED", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationSign, + logical.CreateOperation: b.pathOperationSign, + }, + HelpSynopsis: pathOperationsSignHelpSyn, + HelpDescription: pathOperationsSignHelpDesc, + }, + { + Pattern: "operation/certificate/sign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. Possible options: SHA224_WITH_RSA, SHA256_WITH_RSA, SHA384_WITH_RSA or SHA512_WITH_RSA", + Required: true, + }, + "commonName": { + Type: framework.TypeString, + Description: "Common Name (Subject CN) on the certificate (e.g. server FQDN or YOUR name)", + Required: true, + }, + "csr": { + Type: framework.TypeString, + Description: "The certificate signing request (csr).", + Required: true, + }, + "certificateAuthority": { + Type: framework.TypeBool, + Description: "The certificate authority: true or false", + Required: false, + }, + "keyUsage": { + Type: framework.TypeString, + Description: "The key usage extension defines the purpose (for example, encipherment, signature, or certificate signing) of the key contained in the certificate. If the public key is used for entity authentication, then the certificate extension should have the key usage Digital signature. This has to be array of [] enums. Possible enums: DIGITAL_SIGNATURE, CONTENT_COMMITMENT, KEY_ENCIPHERMENT, DATA_ENCIPHERMENT, KEY_AGREEMENT, KEY_CERT_SIGN, CRL_SIGN, ENCIPHER_ONLY or DECIPHER_ONLY", + Required: false, + Default: "[]", + }, + "extendedKeyUsage": { + Type: framework.TypeString, + Description: "This extension indicates one or more purposes for which the certified public key may be used, in addition to or in place of the basic purposes indicated in the key usage extension. In general, this extension will appear only in end entity certificates. This has to be array of [] enums. Possible enums: ANY_EXTENDED_KEY_USAGE, SERVER_AUTH, CLIENT_AUTH, CODE_SIGNING, EMAIL_PROTECTION, TIME_STAMPING, CRL_SIGN, OCSP_SIGNING", + Required: false, + Default: "[]", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationCertificateSign, + logical.CreateOperation: b.pathOperationCertificateSign, + }, + HelpSynopsis: pathOperationsCertificateSignHelpSyn, + HelpDescription: pathOperationsCertificateSignHelpDesc, + }, + { + Pattern: "operation/certificate/selfsign/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. Possible options: SHA224_WITH_RSA, SHA256_WITH_RSA, SHA384_WITH_RSA or SHA512_WITH_RSA", + Required: true, + }, + "commonName": { + Type: framework.TypeString, + Description: "Common Name (Subject CN) on the certificate (e.g. server FQDN or YOUR name)", + Required: true, + }, + "validity": { + Type: framework.TypeInt, + Description: "The days from today after which the certificate is not valid. e.g. 365 //valid for 1 year. Default: 365", + Required: true, + }, + "certificateAuthority": { + Type: framework.TypeBool, + Description: "The certificate authority: true or false", + Required: false, + }, + "keyUsage": { + Type: framework.TypeString, + Description: "The key usage extension defines the purpose (for example, encipherment, signature, or certificate signing) of the key contained in the certificate. If the public key is used for entity authentication, then the certificate extension should have the key usage Digital signature. This has to be array of [] enums. Possible enums: DIGITAL_SIGNATURE, CONTENT_COMMITMENT, KEY_ENCIPHERMENT, DATA_ENCIPHERMENT, KEY_AGREEMENT, KEY_CERT_SIGN, CRL_SIGN, ENCIPHER_ONLY or DECIPHER_ONLY", + Required: true, + Default: "[]", + }, + "extendedKeyUsage": { + Type: framework.TypeString, + Description: "This extension indicates one or more purposes for which the certified public key may be used, in addition to or in place of the basic purposes indicated in the key usage extension. In general, this extension will appear only in end entity certificates. This has to be array of [] enums. Possible enums: ANY_EXTENDED_KEY_USAGE, SERVER_AUTH, CLIENT_AUTH, CODE_SIGNING, EMAIL_PROTECTION, TIME_STAMPING, CRL_SIGN, OCSP_SIGNING", + Required: true, + Default: "[]", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationCertificateSelfSign, + logical.CreateOperation: b.pathOperationCertificateSelfSign, + }, + HelpSynopsis: pathOperationsCertificateSelfSignHelpSyn, + HelpDescription: pathOperationsCertificateSelfSignHelpDesc, + }, + { + Pattern: "operation/certificate/request/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the sign key. If a derived key should be used for signing the key password of the master key must be specified.", + Required: false, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm to be used. Possible options: SHA224_WITH_RSA, SHA256_WITH_RSA, SHA384_WITH_RSA or SHA512_WITH_RSA", + Required: true, + }, + "certificateAttributes": { + Type: framework.TypeString, + Description: "The standard attributes of X.500 series the key that should be created. At least one operation (decrypt, sign, unwrap) must be allowed (true). It has to be json object. Possible attributes: commonName, country, stateOrProvinceName, locality, organizationName, organizationUnitName, email, title, surname, givenName, initials, pseudonym, generationQualifier", + Required: true, + }, + "validity": { + Type: framework.TypeInt, + Description: "The days from today after which the certificate is not valid. e.g. 365 //valid for 1 year. Default: 365", + Required: true, + }, + "keyUsage": { + Type: framework.TypeString, + Description: "The key usage extension defines the purpose (for example, encipherment, signature, or certificate signing) of the key contained in the certificate. If the public key is used for entity authentication, then the certificate extension should have the key usage Digital signature. This has to be array of [] enums. Possible enums: DIGITAL_SIGNATURE, CONTENT_COMMITMENT, KEY_ENCIPHERMENT, DATA_ENCIPHERMENT, KEY_AGREEMENT, KEY_CERT_SIGN, CRL_SIGN, ENCIPHER_ONLY or DECIPHER_ONLY", + Required: false, + Default: "[]", + }, + "extendedKeyUsage": { + Type: framework.TypeString, + Description: "This extension indicates one or more purposes for which the certified public key may be used, in addition to or in place of the basic purposes indicated in the key usage extension. In general, this extension will appear only in end entity certificates. This has to be array of [] enums. Possible enums: ANY_EXTENDED_KEY_USAGE, SERVER_AUTH, CLIENT_AUTH, CODE_SIGNING, EMAIL_PROTECTION, TIME_STAMPING, CRL_SIGN, OCSP_SIGNING", + Required: false, + Default: "[]", + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationCertificateRequest, + logical.CreateOperation: b.pathOperationCertificateRequest, + }, + HelpSynopsis: pathOperationsCertificateRequestHelpSyn, + HelpDescription: pathOperationsCertificateRequestHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/verify/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "The password of the master key, if the master key has a password set.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in sign request", + Required: true, + }, + "signatureAlgorithm": { + Type: framework.TypeString, + Description: "The signature algorithm that was used to sign the payload.", + Required: true, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload for which the signature was created. It has to be base64 encoded", + Required: true, + }, + "signature": { + Type: framework.TypeString, + Description: "The signature to be verified.", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationVerify, + logical.CreateOperation: b.pathOperationVerify, + }, + HelpSynopsis: pathOperationsVerifyHelpSyn, + HelpDescription: pathOperationsVerifyHelpDesc, + }, + { + Pattern: "operation/encrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "payload": { + Type: framework.TypeString, + Description: "Payload to encrypt. It has to be base64 encoded", + Required: true, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationEncrypt, + logical.CreateOperation: b.pathOperationEncrypt, + }, + HelpSynopsis: pathOperationsEncryptHelpSyn, + HelpDescription: pathOperationsEncryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("keyVersion"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeLowerCaseString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + { + Pattern: "operation/decrypt/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the decrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "keyVersion": { + Type: framework.TypeString, + Description: "Key Version that returned in encrypt request", + Required: true, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "Cipher Algorithm", + Required: true, + }, + "encryptedPayload": { + Type: framework.TypeString, + Description: "Encrypted data to decrypt. It has to be base64 encoded", + Required: true, + }, + "initializationVector": { + Type: framework.TypeString, + Description: "The initialization vector (base64 encoded) used to encrypt the payload. Can be empty if the cipher algorithm used does not require an initialization vector.", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + }, + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathOperationDecrypt, + logical.CreateOperation: b.pathOperationDecrypt, + }, + HelpSynopsis: pathOperationsDecryptHelpSyn, + HelpDescription: pathOperationsDecryptHelpDesc, + }, + } +} + +// This function sends command to HSM to unwrap key +func (b *SecurosysBackend) pathOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationUnWrap(ctx, req, d) + } + } + } + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + if hasPolicy == true { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy) + } else { + _, errEnc = client.UnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil) + } + if errEnc != nil { + return nil, errEnc + } + key, err := client.GetKey(unwrappedKeyEntry.BaseLabel+"_v1", "") + if err != nil { + return nil, err + } + unwrappedKeyVersion.Policy = key.Policy + unwrappedKeyVersion.PublicKey = key.PublicKey + unwrappedKeyEntry.Algorithm = key.Algorithm + unwrappedKeyEntry.Attributes = key.Attributes + unwrappedKeyEntry.KeySize = key.KeySize + unwrappedKeyVersion.Xml = key.Xml + unwrappedKeyVersion.XmlSignature = key.XmlSignature + unwrappedKeyVersion.AttestationKeyName = key.AttestationKeyName + unwrappedKeyVersion.KeyLabel = key.Label + unwrappedKeyEntry.CurrentVersion = "v1" + unwrappedKeyVersion.Version = "v1" + + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + unwrappedKeyEntry.Updated.Aliases = entity.Aliases + unwrappedKeyEntry.Updated.Id = entity.ID + unwrappedKeyEntry.Updated.Name = entity.Name + unwrappedKeyEntry.Created.Aliases = entity.Aliases + unwrappedKeyEntry.Created.Id = entity.ID + unwrappedKeyEntry.Created.Name = entity.Name + } else { + unwrappedKeyEntry.Updated.Id = "root" + unwrappedKeyEntry.Updated.Name = "root" + unwrappedKeyEntry.Updated.Aliases = nil + unwrappedKeyEntry.Created.Aliases = nil + unwrappedKeyEntry.Created.Id = "root" + unwrappedKeyEntry.Created.Name = "root" + } + unwrappedKeyVersion.Updated = unwrappedKeyEntry.Updated + unwrappedKeyVersion.Created = unwrappedKeyEntry.Created + unwrappedKeyEntry.Versions = make(map[string]helpers.KeyVersion) + unwrappedKeyEntry.Versions[unwrappedKeyEntry.CurrentVersion] = unwrappedKeyVersion + + if err := SetKey(ctx, req.Storage, newKeyName, unwrappedKeyEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: unwrappedKeyEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to wrap key +func (b *SecurosysBackend) pathOperationWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyToBeWrappedName := d.Get("keyToBeWrapped").(string) + keyToBeWrappedEntry, err := b.GetKey(ctx, req.Storage, keyToBeWrappedName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyToBeWrappedEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + wrapKeyName := d.Get("wrappedKeyName").(string) + keywrapEntry, err := b.GetKey(ctx, req.Storage, wrapKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keywrapEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keywrapEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keywrapEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keywrapEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", wrapKeyName, keywrapEntry.GetActiveVersion().KeyLabel) + + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keywrapEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + if wrapMethod.(string) == "AES_WRAP" || wrapMethod.(string) == "AES_WRAP_PAD" { + if keyToBeWrappedEntry.Algorithm != "AES" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_DSA" || wrapMethod.(string) == "AES_WRAP_PAD_DSA" { + if keyToBeWrappedEntry.Algorithm != "DSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_EC" || wrapMethod.(string) == "AES_WRAP_PAD_EC" { + if keyToBeWrappedEntry.Algorithm != "EC" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_ED" || wrapMethod.(string) == "AES_WRAP_PAD_ED" { + + if keyToBeWrappedEntry.Algorithm != "ED" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + } + if wrapMethod.(string) == "AES_WRAP_RSA" || wrapMethod.(string) == "AES_WRAP_PAD_RSA" { + if keyToBeWrappedEntry.Algorithm != "RSA" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + if wrapMethod.(string) == "AES_WRAP_BLS" || wrapMethod.(string) == "AES_WRAP_PAD_BLS" { + if keyToBeWrappedEntry.Algorithm != "BLS" { + return nil, fmt.Errorf("You cannot use wrap method %s for wrapping key %s. Key to be wrapped is %s", wrapMethod.(string), keyToBeWrappedName, keyToBeWrappedEntry.Algorithm) + } + + } + } + if keywrapEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keywrapEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + if !helpers.Contains(helpers.SYMMETRIC_KEY_TYPES, keyToBeWrappedEntry.Algorithm) { + return nil, fmt.Errorf("You cannot use assymetric keys for %s wrap method. Your key type %s, available:%s", wrapMethod, keyToBeWrappedEntry.Algorithm, helpers.SYMMETRIC_KEY_TYPES) + + } + } + keyToBeWrappedPassword, ok := d.GetOk("keyToBeWrappedPassword") + keyToBeWrappedPasswordString := "" + if ok { + keyToBeWrappedPasswordString = keyToBeWrappedPassword.(string) + } + wrapKeyPassword, ok := d.GetOk("wrapKeyPassword") + wrapKeyPasswordString := "" + if ok { + wrapKeyPasswordString = wrapKeyPassword.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, _, errEnc := client.Wrap(keywrapEntry.GetActiveVersion().KeyLabel, wrapKeyPasswordString, keyToBeWrappedEntry.GetActiveVersion().KeyLabel, keyToBeWrappedPasswordString, wrapMethod.(string)) + if errEnc != nil { + return nil, errEnc + } + + result.KeyVersion = keywrapEntry.CurrentVersion + var inInterface map[string]interface{} + inrec, _ := json.Marshal(result) + json.Unmarshal(inrec, &inInterface) + + return &logical.Response{ + Data: inInterface, + }, nil +} + +// This function sends command to HSM to encrypt payload using selected key +func (b *SecurosysBackend) pathOperationEncrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload.(string)) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, _, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + result.KeyVersion = keyEntry.CurrentVersion + var inInterface map[string]interface{} + inrec, _ := json.Marshal(result) + json.Unmarshal(inrec, &inInterface) + + return &logical.Response{ + Data: inInterface, + }, nil +} + +// This function sends command to HSM to sign payload using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, _, errEnc := client.AsyncSign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string), map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, _, errReq := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Sign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["payload"] = payload.(string) + requestEntry.Request["payloadType"] = payloadType.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to sign payload using selected key. +func (b *SecurosysBackend) pathOperationSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + payloadType, ok := d.GetOk("payloadType") + if !ok { + payloadType = "UNSPECIFIED" + } + if !helpers.Contains(helpers.SUPPORTED_PAYLOAD_TYPE, payloadType.(string)) { + return nil, fmt.Errorf("Not supported payload type %s. Available payload types %s", payloadType, helpers.SUPPORTED_PAYLOAD_TYPE) + + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, _, errEnc := client.Sign(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload.(string), payloadType.(string), signatureAlgorithm.(string)) + if errEnc != nil { + return nil, errEnc + } + result.KeyVersion = keyEntry.CurrentVersion + var inInterface map[string]interface{} + inrec, _ := json.Marshal(result) + json.Unmarshal(inrec, &inInterface) + + return &logical.Response{ + Data: inInterface, + }, nil +} + +// This function sends command to HSM to sign certificate using selected key. +func (b *SecurosysBackend) pathOperationCertificateSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationCertificateSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_CERTIFICATE_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_CERTIFICATE_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + certificateSigningRequest, ok := d.GetOk("csr") + if !ok { + return nil, fmt.Errorf("error: missing csr") + } + commonName, ok := d.GetOk("commonName") + if !ok { + return nil, fmt.Errorf("error: missing commonName") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if !helpers.Contains(helpers.CERTIFICATE_RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available certificate signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.CERTIFICATE_RSA_SIGNATURE_LIST) + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + certificateAuthority, ok := d.GetOk("certificateAuthority") + certificateAuthorityBool := true + if ok { + certificateAuthorityBool = certificateAuthority.(bool) + } + keyUsage, ok := d.GetOk("keyUsage") + keyUsageArray := []string{} + if ok { + json.Unmarshal([]byte(keyUsage.(string)), &keyUsageArray) + for _, enum := range keyUsageArray { + if !helpers.Contains(helpers.SUPPORTED_KEY_USAGE, enum) { + return nil, fmt.Errorf("Not supported keyUsage %s. Available certificate key usage %s", enum, helpers.SUPPORTED_KEY_USAGE) + } + } + } + extendedKeyUsage, ok := d.GetOk("extendedKeyUsage") + extendedKeyUsageArray := []string{} + if ok { + json.Unmarshal([]byte(extendedKeyUsage.(string)), &extendedKeyUsageArray) + for _, enum := range extendedKeyUsageArray { + if !helpers.Contains(helpers.SUPPORTED_EXTENDED_KEY_USAGE, enum) { + return nil, fmt.Errorf("Not supported keyUsage %s. Available certificate key usage %s", enum, helpers.SUPPORTED_EXTENDED_KEY_USAGE) + } + } + } + client, err := b.GetClient(ctx, req.Storage) + result, _, errEnc := client.SignCertificate(keyEntry.GetActiveVersion().KeyLabel, passwordString, signatureAlgorithm.(string), certificateSigningRequest.(string), commonName.(string), keyUsageArray, extendedKeyUsageArray, certificateAuthorityBool) + if errEnc != nil { + return nil, errEnc + } + result.KeyVersion = keyEntry.CurrentVersion + var inInterface map[string]interface{} + inrec, _ := json.Marshal(result) + json.Unmarshal(inrec, &inInterface) + + return &logical.Response{ + Data: inInterface, + }, nil +} + +// This function sends command to HSM to sign certificate using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationCertificateSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_CERTIFICATE_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_CERTIFICATE_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + certificateSigningRequest, ok := d.GetOk("csr") + if !ok { + return nil, fmt.Errorf("error: missing csr") + } + commonName, ok := d.GetOk("commonName") + if !ok { + return nil, fmt.Errorf("error: missing commonName") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if !helpers.Contains(helpers.CERTIFICATE_RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available certificate signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.CERTIFICATE_RSA_SIGNATURE_LIST) + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + certificateAuthority, ok := d.GetOk("certificateAuthority") + certificateAuthorityBool := true + if ok { + certificateAuthorityBool = certificateAuthority.(bool) + } + keyUsage, ok := d.GetOk("keyUsage") + keyUsageArray := []string{} + if ok { + json.Unmarshal([]byte(keyUsage.(string)), &keyUsageArray) + for _, enum := range keyUsageArray { + if !helpers.Contains(helpers.SUPPORTED_KEY_USAGE, enum) { + return nil, fmt.Errorf("Not supported keyUsage %s. Available certificate key usage %s", enum, helpers.SUPPORTED_KEY_USAGE) + } + } + } + extendedKeyUsage, ok := d.GetOk("extendedKeyUsage") + extendedKeyUsageArray := []string{} + if ok { + json.Unmarshal([]byte(extendedKeyUsage.(string)), &extendedKeyUsageArray) + for _, enum := range extendedKeyUsageArray { + if !helpers.Contains(helpers.SUPPORTED_EXTENDED_KEY_USAGE, enum) { + return nil, fmt.Errorf("Not supported keyUsage %s. Available certificate key usage %s", enum, helpers.SUPPORTED_EXTENDED_KEY_USAGE) + } + } + } + client, err := b.GetClient(ctx, req.Storage) + requestId, _, errEnc := client.AsyncSignCertificate(keyEntry.GetActiveVersion().KeyLabel, passwordString, signatureAlgorithm.(string), certificateSigningRequest.(string), commonName.(string), keyUsageArray, extendedKeyUsageArray, certificateAuthorityBool, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, _, errReq := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "CertificateSign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["commonName"] = commonName.(string) + requestEntry.Request["csr"] = certificateAuthority.(string) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + requestEntry.Request["certificateAuthorityBool"] = strconv.FormatBool(certificateAuthorityBool) + requestEntry.Request["keyUsage"] = strings.Join(keyUsageArray[:], ", ") + requestEntry.Request["extendedKeyUsage"] = strings.Join(extendedKeyUsageArray[:], ", ") + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to self sign certificate using selected key. +func (b *SecurosysBackend) pathOperationCertificateSelfSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationCertificateSelfSign(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_CERTIFICATE_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_CERTIFICATE_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + validity, ok := d.GetOk("validity") + validityInt := 365 + if ok { + validityInt = validity.(int) + } + commonName, ok := d.GetOk("commonName") + if !ok { + return nil, fmt.Errorf("error: missing commonName") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if !helpers.Contains(helpers.CERTIFICATE_RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available certificate signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.CERTIFICATE_RSA_SIGNATURE_LIST) + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + certificateAuthority, ok := d.GetOk("certificateAuthority") + certificateAuthorityBool := true + if ok { + certificateAuthorityBool = certificateAuthority.(bool) + } + keyUsage, ok := d.GetOk("keyUsage") + keyUsageArray := []string{} + if ok { + json.Unmarshal([]byte(keyUsage.(string)), &keyUsageArray) + if len(keyUsageArray) == 0 { + return nil, fmt.Errorf("Not provided any of keyUsage attribute. Supported attributes: %s", helpers.SUPPORTED_KEY_USAGE) + } + for _, enum := range keyUsageArray { + if !helpers.Contains(helpers.SUPPORTED_KEY_USAGE, enum) { + return nil, fmt.Errorf("Not supported keyUsage %s. Available certificate key usage %s", enum, helpers.SUPPORTED_KEY_USAGE) + } + } + } + extendedKeyUsage, ok := d.GetOk("extendedKeyUsage") + extendedKeyUsageArray := []string{} + if ok { + json.Unmarshal([]byte(extendedKeyUsage.(string)), &extendedKeyUsageArray) + if len(extendedKeyUsageArray) == 0 { + return nil, fmt.Errorf("Not provided any of extendedKeyUsage attribute. Supported attributes: %s", helpers.SUPPORTED_EXTENDED_KEY_USAGE) + } + for _, enum := range extendedKeyUsageArray { + if !helpers.Contains(helpers.SUPPORTED_EXTENDED_KEY_USAGE, enum) { + return nil, fmt.Errorf("Not supported extendedKeyUsage %s. Available certificate key usage %s", enum, helpers.SUPPORTED_EXTENDED_KEY_USAGE) + } + } + } + client, err := b.GetClient(ctx, req.Storage) + result, _, errEnc := client.CreateSelfSignedCertificate(keyEntry.GetActiveVersion().KeyLabel, passwordString, signatureAlgorithm.(string), validityInt, commonName.(string), keyUsageArray, extendedKeyUsageArray, certificateAuthorityBool) + if errEnc != nil { + return nil, errEnc + } + result.KeyVersion = keyEntry.CurrentVersion + var inInterface map[string]interface{} + inrec, _ := json.Marshal(result) + json.Unmarshal(inrec, &inInterface) + + return &logical.Response{ + Data: inInterface, + }, nil +} + +// This function sends command to HSM to self sign certificate using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationCertificateSelfSign(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_CERTIFICATE_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_CERTIFICATE_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + validity, ok := d.GetOk("validity") + validityInt := 365 + if !ok { + validityInt = validity.(int) + } + commonName, ok := d.GetOk("commonName") + if !ok { + return nil, fmt.Errorf("error: missing commonName") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if !helpers.Contains(helpers.CERTIFICATE_RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available certificate signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.CERTIFICATE_RSA_SIGNATURE_LIST) + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + certificateAuthority, ok := d.GetOk("certificateAuthority") + certificateAuthorityBool := true + if ok { + certificateAuthorityBool = certificateAuthority.(bool) + } + keyUsage, ok := d.GetOk("keyUsage") + keyUsageArray := []string{} + if ok { + json.Unmarshal([]byte(keyUsage.(string)), &keyUsageArray) + if len(keyUsageArray) == 0 { + return nil, fmt.Errorf("Not provided any of keyUsage attribute. Supported attributes: %s", helpers.SUPPORTED_KEY_USAGE) + } + for _, enum := range keyUsageArray { + if !helpers.Contains(helpers.SUPPORTED_KEY_USAGE, enum) { + return nil, fmt.Errorf("Not supported keyUsage %s. Available certificate key usage %s", enum, helpers.SUPPORTED_KEY_USAGE) + } + } + } + extendedKeyUsage, ok := d.GetOk("extendedKeyUsage") + extendedKeyUsageArray := []string{} + if ok { + json.Unmarshal([]byte(extendedKeyUsage.(string)), &extendedKeyUsageArray) + if len(extendedKeyUsageArray) == 0 { + return nil, fmt.Errorf("Not provided any of extendedKeyUsage attribute. Supported attributes: %s", helpers.SUPPORTED_EXTENDED_KEY_USAGE) + } + for _, enum := range extendedKeyUsageArray { + if !helpers.Contains(helpers.SUPPORTED_EXTENDED_KEY_USAGE, enum) { + return nil, fmt.Errorf("Not supported extendedKeyUsage %s. Available certificate key usage %s", enum, helpers.SUPPORTED_EXTENDED_KEY_USAGE) + } + } + } + client, err := b.GetClient(ctx, req.Storage) + requestId, _, errEnc := client.AsyncSelfSignedCertificate(keyEntry.GetActiveVersion().KeyLabel, passwordString, signatureAlgorithm.(string), validityInt, commonName.(string), keyUsageArray, extendedKeyUsageArray, certificateAuthorityBool, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, _, errReq := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "CertificateSelfSign" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["commonName"] = commonName.(string) + requestEntry.Request["validity"] = fmt.Sprintf("%d", validityInt) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + requestEntry.Request["certificateAuthorityBool"] = strconv.FormatBool(certificateAuthorityBool) + requestEntry.Request["keyUsage"] = strings.Join(keyUsageArray[:], ", ") + requestEntry.Request["extendedKeyUsage"] = strings.Join(extendedKeyUsageArray[:], ", ") + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to creates certificate request using selected key. +func (b *SecurosysBackend) pathOperationCertificateRequest(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if len(keyEntry.GetActiveVersion().Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetActiveVersion().Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationCertificateRequest(ctx, req, d) + } + } + } + + if !helpers.Contains(helpers.SUPPORTED_CERTIFICATE_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_CERTIFICATE_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + validity, ok := d.GetOk("validity") + validityInt := 365 + if !ok { + validityInt = validity.(int) + } + certificateAttributes, ok := d.GetOk("certificateAttributes") + if !ok { + return nil, fmt.Errorf("error: missing certificateAttributes") + } + certificateAttributesObj := helpers.CertificateAttributes{} + if ok { + err := json.Unmarshal([]byte(certificateAttributes.(string)), &certificateAttributesObj) + if err != nil { + return nil, fmt.Errorf("Something wrong on mapping JSON to Object. Error: %s", err.Error()) + } + } + + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if !helpers.Contains(helpers.CERTIFICATE_RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available certificate signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.CERTIFICATE_RSA_SIGNATURE_LIST) + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + keyUsage, ok := d.GetOk("keyUsage") + keyUsageArray := []string{} + if ok { + json.Unmarshal([]byte(keyUsage.(string)), &keyUsageArray) + for _, enum := range keyUsageArray { + if !helpers.Contains(helpers.SUPPORTED_KEY_USAGE, enum) { + return nil, fmt.Errorf("Not supported keyUsage %s. Available certificate key usage %s", enum, helpers.SUPPORTED_KEY_USAGE) + } + } + } + extendedKeyUsage, ok := d.GetOk("extendedKeyUsage") + extendedKeyUsageArray := []string{} + if ok { + json.Unmarshal([]byte(extendedKeyUsage.(string)), &extendedKeyUsageArray) + for _, enum := range extendedKeyUsageArray { + if !helpers.Contains(helpers.SUPPORTED_EXTENDED_KEY_USAGE, enum) { + return nil, fmt.Errorf("Not supported extendedKeyUsage %s. Available certificate key usage %s", enum, helpers.SUPPORTED_EXTENDED_KEY_USAGE) + } + } + } + client, err := b.GetClient(ctx, req.Storage) + result, _, errEnc := client.CreateCertificate(keyEntry.GetActiveVersion().KeyLabel, passwordString, signatureAlgorithm.(string), validityInt, certificateAttributesObj, keyUsageArray, extendedKeyUsageArray) + if errEnc != nil { + return nil, errEnc + } + result.KeyVersion = keyEntry.CurrentVersion + var inInterface map[string]interface{} + inrec, _ := json.Marshal(result) + json.Unmarshal(inrec, &inInterface) + + return &logical.Response{ + Data: inInterface, + }, nil +} + +// This function sends command to HSM to creates certificate request using selected key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationCertificateRequest(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_CERTIFICATE_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_CERTIFICATE_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + validity, ok := d.GetOk("validity") + validityInt := 365 + if !ok { + validityInt = validity.(int) + } + certificateAttributes, ok := d.GetOk("certificateAttributes") + if !ok { + return nil, fmt.Errorf("error: missing certificateAttributes") + } + certificateAttributesObj := helpers.CertificateAttributes{} + if ok { + err := json.Unmarshal([]byte(certificateAttributes.(string)), &certificateAttributesObj) + if err != nil { + return nil, fmt.Errorf("Something wrong on mapping JSON to Object. Error: %s", err.Error()) + } + } + + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if !helpers.Contains(helpers.CERTIFICATE_RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available certificate signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.CERTIFICATE_RSA_SIGNATURE_LIST) + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + keyUsage, ok := d.GetOk("keyUsage") + keyUsageArray := []string{} + if ok { + json.Unmarshal([]byte(keyUsage.(string)), &keyUsageArray) + for _, enum := range keyUsageArray { + if !helpers.Contains(helpers.SUPPORTED_KEY_USAGE, enum) { + return nil, fmt.Errorf("Not supported keyUsage %s. Available certificate key usage %s", enum, helpers.SUPPORTED_KEY_USAGE) + } + } + } + extendedKeyUsage, ok := d.GetOk("extendedKeyUsage") + extendedKeyUsageArray := []string{} + if ok { + json.Unmarshal([]byte(extendedKeyUsage.(string)), &extendedKeyUsageArray) + for _, enum := range extendedKeyUsageArray { + if !helpers.Contains(helpers.SUPPORTED_EXTENDED_KEY_USAGE, enum) { + return nil, fmt.Errorf("Not supported extendedKeyUsage %s. Available certificate key usage %s", enum, helpers.SUPPORTED_EXTENDED_KEY_USAGE) + } + } + } + client, err := b.GetClient(ctx, req.Storage) + requestId, _, errEnc := client.AsyncCreateCertificate(keyEntry.GetActiveVersion().KeyLabel, passwordString, signatureAlgorithm.(string), validityInt, certificateAttributesObj, keyUsageArray, extendedKeyUsageArray, map[string]string{}) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, _, errReq := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "CertificateRequest" + requestEntry.Key = *keyEntry + requestEntry.KeyPassword = passwordString + + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetActiveVersion().KeyLabel + requestEntry.Request["certificateAttributes"] = certificateAttributes.(string) + requestEntry.Request["validity"] = fmt.Sprintf("%d", validityInt) + requestEntry.Request["signatureAlgorithm"] = signatureAlgorithm.(string) + requestEntry.Request["keyUsage"] = strings.Join(keyUsageArray[:], ", ") + requestEntry.Request["extendedKeyUsage"] = strings.Join(extendedKeyUsageArray[:], ", ") + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to verify payload using signature +func (b *SecurosysBackend) pathOperationVerify(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_SIGN_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_SIGN_KEYS) + } + if !keyEntry.Attributes["sign"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute sign is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload, ok := d.GetOk("payload") + if !ok { + return nil, fmt.Errorf("error: missing payload") + } + _, errB64 := b64.StdEncoding.DecodeString(payload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: payload is not valid base64 string") + } + signatureAlgorithm, ok := d.GetOk("signatureAlgorithm") + if !ok { + return nil, fmt.Errorf("error: missing signatureAlgorithm") + } + if keyEntry.Algorithm == "EC" { + if !helpers.Contains(helpers.EC_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported algorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.EC_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "ED" { + if !helpers.Contains(helpers.ED_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.ED_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.RSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "DSA" { + if !helpers.Contains(helpers.DSA_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.DSA_SIGNATURE_LIST) + } + } + if keyEntry.Algorithm == "BLS" { + if !helpers.Contains(helpers.BLS_SIGNATURE_LIST, signatureAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported signatureAlgorithm %s for %s key type. Available signature algorithms %s", signatureAlgorithm, keyEntry.Algorithm, helpers.BLS_SIGNATURE_LIST) + } + } + signature, ok := d.GetOk("signature") + if !ok { + return nil, fmt.Errorf("error: missing signature") + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, _, errEnc := client.Verify(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, payload.(string), signatureAlgorithm.(string), signature.(string)) + if errEnc != nil { + return nil, errEnc + } + + return &logical.Response{ + Data: map[string]interface{}{"signatureValid": result}, + }, nil +} + +// This function sends command to HSM to unwrap key. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationUnWrap(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + + newKeyName := d.Get("unwrappedKeyName").(string) + unwrappedKeyEntry, err := b.GetKey(ctx, req.Storage, newKeyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if unwrappedKeyEntry == nil { + unwrappedKeyEntry = &helpers.KeyEntry{} + } + + if !helpers.Contains(helpers.SUPPORTED_WRAP_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_WRAP_KEYS) + } + if !keyEntry.Attributes["unwrap"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute unwrap is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + if attributes, ok := d.GetOk("attributes"); ok { + err := json.Unmarshal([]byte(attributes.(string)), &unwrappedKeyEntry.Attributes) + if err != nil { + return nil, fmt.Errorf("%s = error on decoding json: %s", "attributes", err.Error()) + } + var counter int = 0 + val1, ok1 := unwrappedKeyEntry.Attributes["decrypt"] + if !ok1 || val1 == false { + counter = counter + 1 + } + val2, ok2 := unwrappedKeyEntry.Attributes["sign"] + if !ok2 || val2 == false { + counter = counter + 1 + } + val3, ok3 := unwrappedKeyEntry.Attributes["unwrap"] + if !ok3 || val3 == false { + counter = counter + 1 + } + if counter == 3 { + return nil, fmt.Errorf("Attributes is not valid. At least one operation (decrypt, sign, unwrap) must be allowed (true). %v", unwrappedKeyEntry.Attributes) + } + _, ok4 := unwrappedKeyEntry.Attributes["destroyable"] + if !ok4 { + unwrappedKeyEntry.Attributes["destroyable"] = true + } + _, ok5 := unwrappedKeyEntry.Attributes["modifiable"] + if !ok5 { + unwrappedKeyEntry.Attributes["modifiable"] = true + } + } else if !ok { + return nil, fmt.Errorf("missing attributes in key") + } + keyLabel, ok := d.GetOk("keyLabel") + if !ok { + return nil, fmt.Errorf("error: missing keyLabel") + } else { + unwrappedKeyEntry.BaseLabel = keyLabel.(string) + } + wrappedKey, ok := d.GetOk("wrappedKey") + if !ok { + return nil, fmt.Errorf("error: missing wrappedKey") + } + wrapMethod, ok := d.GetOk("wrapMethod") + if !ok { + return nil, fmt.Errorf("error: missing wrapMethod") + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.AES_WRAP_METHODS_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_WRAP_METHODS_LIST, wrapMethod.(string)) { + return nil, fmt.Errorf("Not supported wrap method %s for %s key type. Available wrap methods %s", wrapMethod, keyEntry.Algorithm, helpers.RSA_WRAP_METHODS_LIST) + } + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + var hasPolicy bool = false + var unwrappedKeyVersion helpers.KeyVersion + + if simplePolicy, ok := d.GetOk("simplePolicy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(simplePolicy.(string), true) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if policy, ok := d.GetOk("policy"); ok { + if unwrappedKeyEntry.Attributes["extractable"] { + return nil, fmt.Errorf("Error on generating key: attribute 'extractable' is set to true. You cannot use policy with this attribute") + } + policyObj, err := helpers.PreparePolicy(policy.(string), false) + if err != nil { + return nil, fmt.Errorf("Error on generating key policy from '%s' attribute: %s", "simplePolicy", err.Error()) + } + unwrappedKeyVersion.Policy = *policyObj + hasPolicy = true + } + if hasPolicy == false { + policyObj, _ := helpers.PreparePolicy("{}", true) + unwrappedKeyVersion.Policy = *policyObj + } + + client, err := b.GetClient(ctx, req.Storage) + var errEnc error + var requestId string + if hasPolicy == true { + requestId, _, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), &unwrappedKeyVersion.Policy, map[string]string{}) + } else { + requestId, _, errEnc = client.AsyncUnWrap(wrappedKey.(string), unwrappedKeyEntry.BaseLabel+"_v1", unwrappedKeyEntry.Attributes, keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, wrapMethod.(string), nil, map[string]string{}) + } + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, _, errReq := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "UnWrap" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["unwrapedKey"] = newKeyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["unwrapKeyName"] = unwrappedKeyEntry.BaseLabel + "_v1" + requestEntry.Request["wrappedKey"] = wrappedKey.(string) + requestEntry.Request["wrapMethod"] = wrapMethod.(string) + requestEntry.Request["attributes"] = fmt.Sprintf("%v", unwrappedKeyEntry.Attributes) + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. This command is only use, when key have a policy with Use Rule +func (b *SecurosysBackend) pathAsyncOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + requestId, _, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString, nil) + if errEnc != nil { + return nil, errEnc + } + var requestEntry helpers.RequestEntry + requestResponse, _, errReq := client.GetRequest(requestId) + if errReq != nil { + return nil, errReq + } + sysView := b.System() + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + requestEntry.Updated.Aliases = entity.Aliases + requestEntry.Updated.Id = entity.ID + requestEntry.Updated.Name = entity.Name + requestEntry.Created.Aliases = entity.Aliases + requestEntry.Created.Id = entity.ID + requestEntry.Created.Name = entity.Name + } else { + requestEntry.Updated.Id = "root" + requestEntry.Updated.Name = "root" + requestEntry.Updated.Aliases = nil + requestEntry.Created.Id = "root" + requestEntry.Created.Name = "root" + requestEntry.Created.Aliases = nil + } + + requestEntry.Id = requestResponse.Id + requestEntry.Type = "Decrypt" + requestEntry.Key = *keyEntry + requestEntry.KeyVersion = keyEntry.CurrentVersion + requestEntry.KeyPassword = passwordString + + requestEntry.UpdateStatus(*requestResponse) + requestEntry.Request = make(map[string]string) + requestEntry.Request["key"] = keyName + requestEntry.Request["keyLabel"] = keyEntry.GetVersion(keyVersion.(string)).KeyLabel + requestEntry.Request["encryptedPayload"] = encryptedPayload.(string) + requestEntry.Request["initializationVector"] = initializationVectorString + requestEntry.Request["cipherAlgorithm"] = cipherAlgorithm.(string) + requestEntry.Request["tagLength"] = strconv.Itoa(tagLengthInt) + requestEntry.Request["additionalAuthenticationData"] = additionalAuthenticationDataString + + if err := setRequest(ctx, req.Storage, requestResponse.Id, &requestEntry); err != nil { + return nil, err + } + return &logical.Response{ + Data: requestEntry.ToResponseData(), + }, nil +} + +// This function sends command to HSM to decrypt payload. +func (b *SecurosysBackend) pathOperationDecrypt(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyName := d.Get("name").(string) + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + keyVersion, ok := d.GetOk("keyVersion") + if !ok { + return nil, fmt.Errorf("error: missing keyVersion") + } + if !helpers.ContainsKey(keyEntry.Versions, keyVersion) { + return nil, fmt.Errorf("Key version %s is not exists.", keyVersion) + + } + if len(keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(keyVersion.(string)).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + return b.pathAsyncOperationDecrypt(ctx, req, d) + } + } + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload, ok := d.GetOk("encryptedPayload") + if !ok { + return nil, fmt.Errorf("error: missing encryptedPayload") + } + _, errB64 := b64.StdEncoding.DecodeString(encryptedPayload.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: encryptedPayload is not valid base64 string") + } + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVector, ok := d.GetOk("initializationVector") + initializationVectorString := "" + if ok { + initializationVectorString = initializationVector.(string) + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, _, errEnc := client.Decrypt(keyEntry.GetVersion(keyVersion.(string)).KeyLabel, passwordString, encryptedPayload.(string), initializationVectorString, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result.Payload) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + result.Payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(result.Payload) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + result.Payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + var inInterface map[string]interface{} + inrec, _ := json.Marshal(result) + json.Unmarshal(inrec, &inInterface) + + return &logical.Response{ + Data: inInterface, + }, nil +} diff --git a/backend/path_hsm_requests.go b/backend/path_hsm_requests.go new file mode 100644 index 0000000..683836e --- /dev/null +++ b/backend/path_hsm_requests.go @@ -0,0 +1,298 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Path for storing requests for async key operation +func pathRequests(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "requests/?$", + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathRequestsList, + }, + }, + HelpSynopsis: pathRequestListHelpSynopsis, + HelpDescription: pathRequestListHelpDescription, + }, { + Pattern: "requests/" + framework.GenericNameRegex("id"), + Fields: map[string]*framework.FieldSchema{ + "id": { + Type: framework.TypeLowerCaseString, + Description: "Request ID", + Required: true, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathRequestsRead, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathRequestsDelete, + }, + }, + HelpSynopsis: pathRequestReadDeleteHelpSynopsis, + HelpDescription: pathRequestReadDeleteHelpDescription, + }, + } +} + +// Function thats delete request from Secrets Engine and also on HSM +func (b *SecurosysBackend) pathRequestsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + _, errGet := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if errGet != nil { + return nil, fmt.Errorf("error deleting request: %w", errGet) + } + + client, errClient := b.GetClient(ctx, req.Storage) + if errClient != nil { + return nil, fmt.Errorf("error deleting request key: %w", errClient) + + } + _, errReq := client.RemoveRequest(d.Get("id").(string)) + if errReq != nil { + return nil, fmt.Errorf("error deleting request key: %w", errReq) + + } + + err := req.Storage.Delete(ctx, "requests/"+d.Get("id").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting request key: %w", err) + } + + return nil, nil +} + +// This function read stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entry, err := b.getRequest(ctx, req.Storage, d.Get("id").(string)) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + if entry.Status == "PENDING" { + requestResponse, _, err := b.client.GetRequest(entry.Id) + if err != nil { + entry.Status = "ERROR" + } else { + entry.UpdateStatus(*requestResponse) + } + if entry.Status == "EXECUTED" && entry.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, entry.Type) { + entry.KeyUpdated = true + key, err := b.client.GetKey(entry.Key.Versions[entry.KeyVersion].KeyLabel, entry.Key.Versions[entry.KeyVersion].Password) + if err != nil { + return nil, err + } + entry.Key.UpdateKeyFromHSMWithRequest(key, *entry) + if err := SetKey(ctx, req.Storage, entry.Request["key"], &entry.Key); err != nil { + return nil, err + } + + } + + } + + return &logical.Response{ + Data: entry.ToResponseData(), + }, nil +} + +// This function read all stored requests operation from Secrets Engine +func (b *SecurosysBackend) pathRequestsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "requests/") + if err != nil { + return nil, err + } + requests := make([]string, 0, len(entries)) + requestInfo := make(map[string]interface{}) + for _, name := range entries { + requests = append(requests, name) + request, err := b.getRequest(ctx, req.Storage, name) + if err == nil { + if request.Status == "PENDING" { + requestResponse, _, err := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Key.Versions[request.KeyVersion].KeyLabel, request.Key.Versions[request.KeyVersion].Password) + if err != nil { + return nil, err + } + request.Key.UpdateKeyFromHSMWithRequest(key, *request) + if err := SetKey(ctx, req.Storage, request.Request["key"], &request.Key); err != nil { + return nil, err + } + + } + if request.Status == "EXECUTED" && request.KeyUpdated == false && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + newKey.Versions[newKey.CurrentVersion] = newKeyVersion + if err := SetKey(ctx, req.Storage, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + + } + var notYetApprovedByArray []string = make([]string, len(request.NotYetApprovedBy)) + for name, _ := range request.NotYetApprovedBy { + notYetApprovedByArray = append(notYetApprovedByArray, name) + } + requestInfo[name] = map[string]interface{}{ + "ExecutionTime": request.ExecutionTime, + "Status": request.Status, + "Type": request.Type, + "NotYetApproved": notYetApprovedByArray, + "Created": request.Created.Name, + "Updated": request.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(requests, requestInfo), nil +} + +// This function helps saves requests inside Secrets Engine +func setRequest(ctx context.Context, s logical.Storage, name string, requestEntry *helpers.RequestEntry) error { + entry, err := logical.StorageEntryJSON("requests/"+name, requestEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage entry for request") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting requests from Secrets Engine +func (b *SecurosysBackend) getRequest(ctx context.Context, s logical.Storage, name string) (*helpers.RequestEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing request name") + } + + entry, err := s.Get(ctx, "requests/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, fmt.Errorf("Request with %s not exists", name) + } + + var request helpers.RequestEntry + + if err := entry.DecodeJSON(&request); err != nil { + return nil, err + } + if request.Status == "PENDING" && !helpers.Contains(helpers.UPDATE_POLICY_ON, request.Type) { + requestResponse, _, err := b.client.GetRequest(request.Id) + if err != nil { + request.Status = "ERROR" + } else { + request.UpdateStatus(*requestResponse) + } + setRequest(ctx, s, name, &request) + } + if request.Status == "PENDING" && request.Type == "UnWrap" { + request.KeyUpdated = true + key, err := b.client.GetKey(request.Request["unwrapKeyName"], "") + if err != nil { + return nil, err + } + var newKey helpers.KeyEntry + var newKeyVersion helpers.KeyVersion + newKey.Algorithm = key.Algorithm + newKeyVersion.AttestationKeyName = key.AttestationKeyName + newKey.Attributes = key.Attributes + newKey.CurveOid = key.CurveOid + newKey.CurrentVersion = "v1" + newKey.BaseLabel = strings.Replace(request.Request["unwrapKeyName"], "_v1", "", 1) + newKeyVersion.KeyLabel = request.Request["unwrapKeyName"] + newKey.KeySize = key.KeySize + newKeyVersion.Policy = key.Policy + newKeyVersion.PublicKey = key.PublicKey + newKeyVersion.Xml = key.Xml + newKeyVersion.Version = "v1" + newKeyVersion.XmlSignature = key.XmlSignature + + created := request.Created + created.Date = time.Now() + newKey.Created = created + newKey.Updated = created + newKeyVersion.Created = created + newKeyVersion.Updated = created + + if err := SetKey(ctx, s, request.Request["unwrapedKey"], &newKey); err != nil { + return nil, err + } + + } + return &request, nil +} diff --git a/backend/path_mariadb_integration.go b/backend/path_mariadb_integration.go new file mode 100644 index 0000000..881d768 --- /dev/null +++ b/backend/path_mariadb_integration.go @@ -0,0 +1,666 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package backend + +import ( + "context" + "encoding/base64" + b64 "encoding/base64" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/andreburgaud/crypt2go/padding" + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + helpers "securosys.ch/helpers" +) + +// Paths for create Camellia Keys +func pathMariaDBIntegration(b *SecurosysBackend) []*framework.Path { + return []*framework.Path{ + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "keyName": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipherAlgorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tagLength": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "additionalAuthenticationData": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.CreateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsWrite, + }, + logical.DeleteOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsDelete, + }, + }, + HelpSynopsis: pathIntegrationMariaDBWriteHelpSynopsis, + HelpDescription: pathIntegrationMariaDBWriteHelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/" + framework.GenericNameRegex("version") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV1HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV1HelpDescription, + }, + { + Pattern: "integrations/mariadb/" + framework.GenericNameRegex("name") + "/?" + framework.MatchAllRegex("query"), + Fields: map[string]*framework.FieldSchema{ + "name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the secret", + Required: true, + }, + "query": { + Type: framework.TypeString, + Description: "Additional query params", + Required: false, + }, + "key_name": { + Type: framework.TypeLowerCaseString, + Description: "Name of the key on Vault", + Required: true, + }, + "password": { + Type: framework.TypeString, + Description: "Password of the encrypt key. This is only necessary if the key algorithm is symmetric.", + Required: false, + }, + "cipher_algorithm": { + Type: framework.TypeString, + Description: "The cipher algorithm to be used.", + Required: true, + }, + "tag_length": { + Type: framework.TypeInt, + Description: "The MAC (Message Authentication Tag) is a fixed-length value as part of the AES-GCM encryption process, that is INCLUDED in the encryptedPayload and used to authenticatethe integrity of the data and the authenticity of the sender. Supported tag_length: 0, 64, 96, 104, 112, 120, 128", + Required: false, + }, + "aad": { + Type: framework.TypeString, + Description: "Additional authentication data (aad) used when decrypting payload. Can be empty if none were used when encrypting the payload", + Required: false, + }, + "version": { + Type: framework.TypeString, + Description: "Additional data from mariadb plugin", + Required: false, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsRead, + }, + }, + HelpSynopsis: pathIntegrationMariaDBReadV2HelpSynopsis, + HelpDescription: pathIntegrationMariaDBReadV2HelpDescription, + }, + { + Pattern: "integrations/mariadb/?$", + Fields: map[string]*framework.FieldSchema{}, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathIntegrationMariaDBSecretsList, + }, + }, + HelpSynopsis: pathIntegrationMariaDBListHelpSynopsis, + HelpDescription: pathIntegrationMariaDBListHelpDescription, + }, + } +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "intergration/mariadb/") + if err != nil { + return nil, err + } + secrets := make([]string, 0, len(entries)) + secretsInfo := make(map[string]interface{}) + for _, name := range entries { + secrets = append(secrets, name) + secret, err := b.GetMariaDBSecret(ctx, req.Storage, name) + if err == nil { + secretsInfo[name] = map[string]interface{}{ + "KeyName": secret.KeyName, + "Version": secret.CurrentVersion, + "Created": secret.Created.Name, + "Updated": secret.Updated.Name, + } + } + } + return logical.ListResponseWithInfo(secrets, secretsInfo), nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, errGet := b.GetMariaDBSecret(ctx, req.Storage, name) + if errGet != nil { + return nil, fmt.Errorf("error deleting mariadb secret: %w", errGet) + } + if storedSecret == nil { + return nil, fmt.Errorf("error deleting mariadb secret: secret with name %s not exists", d.Get("name").(string)) + + } + + err := req.Storage.Delete(ctx, "intergration/mariadb/"+d.Get("name").(string)) + if err != nil { + return nil, fmt.Errorf("error deleting securosys key: %w", err) + } + + return nil, nil +} + +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + name := d.Get("name").(string) + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + rotate := false + if storedSecret != nil { + rotate = true + // return nil, fmt.Errorf("error secret with name: %s exists", name) + } else { + storedSecret = &helpers.MariaDBSecretEntry{} + + } + + keyName := d.Get("keyName").(string) + + keyEntry, err := b.GetKey(ctx, req.Storage, keyName) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + payload := b64.StdEncoding.EncodeToString([]byte(helpers.GeneratePassword(32, false, false, false, true))) + + cipherAlgorithm, ok := d.GetOk("cipherAlgorithm") + if !ok && keyEntry.KeyTypeName != "aes256-gcm96" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm.(string)) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + + if cipherAlgorithm.(string) == "AES_ECB" || + cipherAlgorithm.(string) == "AES_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "CAMELLIA_ECB" || + cipherAlgorithm.(string) == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm.(string) == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm.(string) == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(payload) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Pad(payloadBytes) + payload = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + password, ok := d.GetOk("password") + passwordString := "" + if ok { + passwordString = password.(string) + } + tagLength, ok := d.GetOk("tagLength") + tagLengthInt := -1 + + if ok && keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt = tagLength.(int) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + + additionalAuthenticationData, ok := d.GetOk("additionalAuthenticationData") + additionalAuthenticationDataString := "" + if ok { + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationData.(string)) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData is not valid base64 string") + } + additionalAuthenticationDataString = additionalAuthenticationData.(string) + } + client, err := b.GetClient(ctx, req.Storage) + result, _, errEnc := client.Encrypt(keyEntry.GetActiveVersion().KeyLabel, passwordString, payload, cipherAlgorithm.(string), tagLengthInt, additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + sysView := b.System() + creator := helpers.Entity{} + if req.EntityID != "" { + entity, _ := sysView.EntityInfo(req.EntityID) + creator.Aliases = entity.Aliases + creator.Id = entity.ID + creator.Name = entity.Name + creator.Date = time.Now().UTC() + + } else { + creator.Aliases = nil + creator.Id = "root" + creator.Name = "root" + creator.Date = time.Now().UTC() + + } + var messageAuthenticationCode *string = nil + if result.MessageAuthenticationCode != nil { + temp := *result.MessageAuthenticationCode + messageAuthenticationCode = &temp + } + var initializationVector *string = nil + if result.InitializationVector != nil { + temp := *result.InitializationVector + initializationVector = &temp + } + if !rotate { + storedSecret.InitSecret(keyName, keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result.EncryptedPayload, creator) + } else { + storedSecret.RotateSecret(keyEntry.CurrentVersion, messageAuthenticationCode, initializationVector, result.EncryptedPayload, creator) + + } + if err := SetMariaDBSecret(ctx, req.Storage, name, storedSecret); err != nil { + return nil, err + } + + response := map[string]interface{}{} + now := storedSecret.GetActiveVersion().Created.Date + version := storedSecret.GetActiveVersion().Version + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} +func (b *SecurosysBackend) pathIntegrationMariaDBSecretsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + query := d.Get("query").(string) + if strings.HasPrefix(query, "?") { + query = query[1:] + } + params, err := url.ParseQuery(query) + + if query == "" { + str := "" + for key, value := range req.Data { + str = str + key + "=" + value.(string) + "&" + } + str = str[:len(str)-1] + params, err = url.ParseQuery(str) + } + + if err != nil { + return nil, err + } + name := d.Get("name").(string) + + storedSecret, _ := b.GetMariaDBSecret(ctx, req.Storage, name) + if storedSecret == nil { + return nil, fmt.Errorf("error secret with name: %s not exists", name) + } + + version := "1" + if params.Has("version") { + if !strings.Contains(params.Get("version"), "?version=") { + version = storedSecret.CurrentVersion + } else { + parts := strings.Split(params.Get("version"), "?version=") + version = "v" + parts[1] + } + } else { + ver, ok := d.GetOk("version") + if !ok { + return nil, fmt.Errorf("error: missing version") + } + version = ver.(string) + } + + if !params.Has("key_name") { + return nil, fmt.Errorf("key_name query param not exists") + } + keyEntry, err := b.GetKey(ctx, req.Storage, params.Get("key_name")) + if err != nil { + return nil, fmt.Errorf("error retrieving key: %w", err) + } + keyName := params.Get("key_name") + if keyEntry == nil { + return nil, errors.New("error retrieving key: key is nil") + } + if !keyEntry.Attributes["decrypt"] { + return nil, fmt.Errorf("Cannot use key %s with HSM label %s. Attribute decrypt is false", keyName, keyEntry.GetActiveVersion().KeyLabel) + + } + + if !helpers.ContainsKey(storedSecret.Versions, version) { + return nil, fmt.Errorf("Secret version %s is not exists.", version) + + } + if !helpers.Contains(helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS, keyEntry.Algorithm) { + return nil, fmt.Errorf("Key type %s is not supported. Available key types %s", keyEntry.Algorithm, helpers.SUPPORTED_ENCRYPT_DECRYPT_KEYS) + } + encryptedPayload := storedSecret.GetVersion(version).EncryptedSecret + + if !params.Has("cipher_algorithm") { + return nil, fmt.Errorf("cipher_algorithm query param not exists") + } + + cipherAlgorithm := params.Get("cipher_algorithm") + if keyEntry.KeyTypeName != "aes256-gcm96" && cipherAlgorithm == "" { + return nil, fmt.Errorf("error: missing cipherAlgorithm") + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + cipherAlgorithm = "AES_GCM" + } + initializationVectorString := "" + if params.Has("initialization_vector") { + initializationVectorString = params.Get("initialization_vector") + } + + if keyEntry.Algorithm == "AES" { + if !helpers.Contains(helpers.AES_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.AES_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "RSA" { + if !helpers.Contains(helpers.RSA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.RSA_CIPHER_LIST) + } + } + if keyEntry.Algorithm == "CHACHA20" { + if !helpers.Contains(helpers.CHACHA20_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CHACHA20_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "CAMELIA" { + if !helpers.Contains(helpers.CAMELIA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.CAMELIA_CIPHER_LIST) + } + + } + if keyEntry.Algorithm == "TDEA" { + if !helpers.Contains(helpers.TDEA_CIPHER_LIST, cipherAlgorithm) { + return nil, fmt.Errorf("Not supported cipherAlgorithm %s for %s key type. Available cipher algorithms %s", cipherAlgorithm, keyEntry.Algorithm, helpers.TDEA_CIPHER_LIST) + } + + } + passwordString := "" + if params.Has("password") { + passwordString = params.Get("password") + } + tagLengthInt := -1 + if params.Has("tag_length") { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + } + if keyEntry.KeyTypeName != "aes256-gcm96" { + tagLengthInt, _ = strconv.Atoi(params.Get("tag_length")) + if tagLengthInt != -1 && keyEntry.Algorithm == "AES" && cipherAlgorithm == "AES_GCM" { + if !helpers.Contains(helpers.SUPPORTED_TAG_LENGTH, strconv.Itoa(tagLengthInt)) { + return nil, fmt.Errorf("Not supported tag length %s. Available tag lengths %s", strconv.Itoa(tagLengthInt), helpers.SUPPORTED_TAG_LENGTH) + } + } + } + if keyEntry.KeyTypeName == "aes256-gcm96" { + tagLengthInt = 96 + } + additionalAuthenticationDataString := "" + if params.Has("aad") { + additionalAuthenticationDataString = params.Get("aad") + _, errB64 := b64.StdEncoding.DecodeString(additionalAuthenticationDataString) + if errB64 != nil { + return nil, fmt.Errorf("error: additionalAuthenticationData (param aad) is not valid base64 string") + } + } + client, err := b.GetClient(ctx, req.Storage) + async := false + decrypted := "" + if len(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens) > 0 { + for _, token := range keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).Policy.RuleUse.Tokens { + if len(token.Groups) > 0 { + async = true + requestId, _, errEnc := client.AsyncDecrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString, map[string]string{"integration": "MariaDB Encrypt"}) + if errEnc != nil { + return nil, errEnc + } + var resp *helpers.RequestResponse + resp, _, _ = client.GetRequest(requestId) + for resp.Status == "PENDING" { + time.Sleep(1000) + resp, _, _ = client.GetRequest(requestId) + } + if resp.Status != "EXECUTED" { + return nil, fmt.Errorf("error on async decrypt. Expected Status '%s' got '%s'", "EXECUTED", resp.Status) + } + decrypted = resp.Result + + } + } + } + if !async { + resultSync, _, errEnc := client.Decrypt(keyEntry.GetVersion(storedSecret.GetVersion(version).KeyVersion).KeyLabel, + passwordString, encryptedPayload, + initializationVectorString, + cipherAlgorithm, + tagLengthInt, + additionalAuthenticationDataString) + if errEnc != nil { + return nil, errEnc + } + decrypted = resultSync.Payload + } + + if cipherAlgorithm == "AES_ECB" || + cipherAlgorithm == "AES_CBC_NO_PADDING" || + cipherAlgorithm == "CAMELLIA_ECB" || + cipherAlgorithm == "CAMELLIA_CBC_NO_PADDING" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(32) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + } + if cipherAlgorithm == "TDEA_CBC_NO_PADDING" || + cipherAlgorithm == "TDEA_ECB" { + payloadBytes, _ := base64.StdEncoding.DecodeString(decrypted) + padder := padding.NewPkcs7Padding(24) + payloadBytes, _ = padder.Unpad(payloadBytes) + decrypted = base64.StdEncoding.EncodeToString(payloadBytes) + + } + + decoded, _ := base64.StdEncoding.DecodeString(decrypted) + response := map[string]interface{}{} + response["data"] = map[string]interface{}{"data": string(decoded)} + now := storedSecret.GetVersion(version).Created.Date + + response["metadata"] = map[string]interface{}{ + "created_time": fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()), + "version": helpers.GetVersionNumber(version)} + return &logical.Response{ + Warnings: nil, + Data: response, + }, nil +} + +// This function helps with saving key in Secrets Engine +func SetMariaDBSecret(ctx context.Context, s logical.Storage, name string, secretEntry *helpers.MariaDBSecretEntry) error { + entry, err := logical.StorageEntryJSON("intergration/mariadb/"+name, secretEntry) + if err != nil { + return err + } + + if entry == nil { + return fmt.Errorf("failed to create storage secret") + } + + if err := s.Put(ctx, entry); err != nil { + return err + } + + return nil +} + +// This function helps with getting key from Secrets Engine +func (b *SecurosysBackend) GetMariaDBSecret(ctx context.Context, s logical.Storage, name string) (*helpers.MariaDBSecretEntry, error) { + if name == "" { + return nil, fmt.Errorf("missing key name") + } + + entry, err := s.Get(ctx, "intergration/mariadb/"+name) + if err != nil { + return nil, err + } + + if entry == nil { + return nil, nil + } + + var secret helpers.MariaDBSecretEntry + + if err := entry.DecodeJSON(&secret); err != nil { + return nil, err + } + return &secret, nil +} diff --git a/client/TSBClient.go b/client/TSBClient.go new file mode 100644 index 0000000..d59931a --- /dev/null +++ b/client/TSBClient.go @@ -0,0 +1,353 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej, Mikolaj Szargut + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/tls" + "crypto/x509" + b64 "encoding/base64" + "encoding/json" + "encoding/pem" + "fmt" + "io" + "io/ioutil" + "log" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TSBClient struct { + HostURL string + HTTPClient *http.Client + Auth AuthStruct +} +type AuthStruct struct { + AppName string `json:"appName"` + AuthType string `json:"auth"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + BearerToken string `json:"bearertoken"` + BasicToken string `json:"basictoken"` + Username string `json:"username"` + Password string `json:"password"` + ApiKeys ApiKeyTypes `json:"apikey"` + ApplicationKeyPair KeyPair `json:"applicationKeyPair"` + CurrentApiKeyTypeIndex ApiKeyTypesRetry +} +type KeyPair struct { + PrivateKey *string `json:"privateKey,omitempty"` + PublicKey *string `json:"publicKey,omitempty"` +} + +type ApiKeyTypes struct { + KeyManagementToken []string `json:"KeyManagementToken,omitempty"` + KeyOperationToken []string `json:"KeyOperationToken,omitempty"` + ApproverToken []string `json:"ApproverToken,omitempty"` + ServiceToken []string `json:"ServiceToken,omitempty"` + ApproverKeyManagementToken []string `json:"ApproverKeyManagementToken,omitempty"` +} +type ApiKeyTypesRetry struct { + KeyManagementTokenIndex int + KeyOperationTokenIndex int + ApproverTokenIndex int + ServiceTokenIndex int + ApproverKeyManagementTokenIndex int +} + +const ( + KeyManagementTokenName = "KeyManagementToken" + KeyOperationTokenName = "KeyOperationToken" + ApproverTokenName = "ApproverToken" + ServiceTokenName = "ServiceToken" + ApproverKeyManagementTokenName = "ApproverKeyManagementToken" +) + +// Function inicialize new client for accessing TSB +func NewTSBClient(restApi string, settings AuthStruct) (*TSBClient, error) { + c := TSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + HostURL: restApi, + Auth: settings, + } + + return &c, nil +} +func (a *TSBClient) RollOverApiKey(name string) error { + switch name { + case "KeyManagementToken": + a.Auth.CurrentApiKeyTypeIndex.KeyManagementTokenIndex += 1 + return nil + case "KeyOperationToken": + if len(a.Auth.ApiKeys.KeyOperationToken) == 0 { + return fmt.Errorf("no KeyOperationToken provided") + } + a.Auth.CurrentApiKeyTypeIndex.KeyOperationTokenIndex += 1 + return nil + case "ApproverToken": + if len(a.Auth.ApiKeys.ApproverToken) == 0 { + return fmt.Errorf("no ApproverToken provided") + } + a.Auth.CurrentApiKeyTypeIndex.ApproverTokenIndex += 1 + return nil + case "ServiceToken": + if len(a.Auth.ApiKeys.ServiceToken) == 0 { + return fmt.Errorf("no ServiceToken provided") + } + a.Auth.CurrentApiKeyTypeIndex.ServiceTokenIndex += 1 + return nil + case "ApproverKeyManagementToken": + if len(a.Auth.ApiKeys.ApproverKeyManagementToken) == 0 { + return fmt.Errorf("no ApproverKeyManagementToken provided") + } + a.Auth.CurrentApiKeyTypeIndex.ApproverKeyManagementTokenIndex += 1 + return nil + } + return fmt.Errorf("apikey usign name %s does not exist", name) + +} + +func (a *TSBClient) CanGetNewApiKeyByName(name string) (bool, error) { + switch name { + case "KeyManagementToken": + if len(a.Auth.ApiKeys.KeyManagementToken) == 0 { + return false, nil + } + if len(a.Auth.ApiKeys.KeyManagementToken) > a.Auth.CurrentApiKeyTypeIndex.KeyManagementTokenIndex { + return true, nil + } + return false, fmt.Errorf("no more apikeys") + case "KeyOperationToken": + if len(a.Auth.ApiKeys.KeyOperationToken) == 0 { + return false, nil + } + if len(a.Auth.ApiKeys.KeyOperationToken) > a.Auth.CurrentApiKeyTypeIndex.KeyOperationTokenIndex { + return true, nil + } + return false, fmt.Errorf("no more apikeys") + case "ApproverToken": + if len(a.Auth.ApiKeys.ApproverToken) == 0 { + return false, nil + } + if len(a.Auth.ApiKeys.ApproverToken) > a.Auth.CurrentApiKeyTypeIndex.ApproverTokenIndex { + return true, nil + } + return false, fmt.Errorf("no more apikeys") + case "ServiceToken": + if len(a.Auth.ApiKeys.ServiceToken) == 0 { + return false, nil + } + if len(a.Auth.ApiKeys.ServiceToken) > a.Auth.CurrentApiKeyTypeIndex.ServiceTokenIndex { + return true, nil + } + return false, fmt.Errorf("no more apikeys") + case "ApproverKeyManagementToken": + if len(a.Auth.ApiKeys.ApproverKeyManagementToken) == 0 { + return false, nil + } + if len(a.Auth.ApiKeys.ApproverKeyManagementToken) > a.Auth.CurrentApiKeyTypeIndex.ApproverKeyManagementTokenIndex { + return true, nil + } + return false, fmt.Errorf("no more apikeys") + } + return false, fmt.Errorf("no apikey exists usign name %s", name) + +} + +func (a *TSBClient) GetApiKeyByName(name string) *string { + switch name { + case "KeyManagementToken": + return &a.Auth.ApiKeys.KeyManagementToken[a.Auth.CurrentApiKeyTypeIndex.KeyManagementTokenIndex] + case "KeyOperationToken": + return &a.Auth.ApiKeys.KeyOperationToken[a.Auth.CurrentApiKeyTypeIndex.KeyOperationTokenIndex] + case "ApproverToken": + return &a.Auth.ApiKeys.ApproverToken[a.Auth.CurrentApiKeyTypeIndex.ApproverTokenIndex] + case "ServiceToken": + return &a.Auth.ApiKeys.ServiceToken[a.Auth.CurrentApiKeyTypeIndex.ServiceTokenIndex] + case "ApproverKeyManagementToken": + return &a.Auth.ApiKeys.ApproverKeyManagementToken[a.Auth.CurrentApiKeyTypeIndex.ApproverKeyManagementTokenIndex] + } + return nil +} + +// Function that making all requests. Using config for Authorization to TSB +func (c *TSBClient) doRequest(req *http.Request, apiKeyName string) ([]byte, int, error) { + // req.Header.Set("Authorization", c.Token) + if c.Auth.AuthType == "TOKEN" { + req.Header.Set("Authorization", "Bearer "+c.Auth.BearerToken) + } + if c.Auth.AuthType == "BASIC" { + if c.Auth.BasicToken == "" { + req.SetBasicAuth(c.Auth.Username, c.Auth.Password) + } else { + req.Header.Set("Authorization", "Basic "+(c.Auth.BasicToken)) + } + } + if c.Auth.AuthType == "CERT" { + + caCert, _ := ioutil.ReadFile(c.Auth.CertPath) + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + clientTLSCert, err := tls.LoadX509KeyPair(c.Auth.CertPath, c.Auth.KeyPath) + if err != nil { + log.Fatalf("Error loading certificate and key file: %v", err) + return nil, 0, err + } + + c.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + InsecureSkipVerify: true, + Certificates: []tls.Certificate{clientTLSCert}, + }, + } + } + canGetApiKey, err := c.CanGetNewApiKeyByName(apiKeyName) + if err != nil { + return []byte(fmt.Sprintf("All apikeys in group %s are invalid", apiKeyName)), 401, fmt.Errorf("status: %d, body: All apikeys in group %s are invalid", 401, apiKeyName) + } + if canGetApiKey { + req.Header.Set("X-API-KEY", *c.GetApiKeyByName(apiKeyName)) + } + + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, res.StatusCode, err + } + defer res.Body.Close() + + body, err := io.ReadAll(res.Body) + if err != nil { + return nil, res.StatusCode, err + } + if canGetApiKey && res.StatusCode == http.StatusUnauthorized { + var result map[string]interface{} + json.Unmarshal(body, &result) + errorCode := result["errorCode"].(float64) + + if errorCode == 631 { + c.RollOverApiKey(apiKeyName) + return c.doRequest(req, apiKeyName) + + } + } + + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, res.StatusCode, fmt.Errorf("status: %d, body: %s", res.StatusCode, body) + } + + return body, res.StatusCode, err +} + +func (c *TSBClient) GetApplicationPrivateKey() *rsa.PrivateKey { + if c.Auth.ApplicationKeyPair.PrivateKey == nil { + return nil + } + block, _ := pem.Decode(c.WrapPrivateKeyWithHeaders(false)) + key, _ := x509.ParsePKCS1PrivateKey(block.Bytes) + if key == nil { + block, _ = pem.Decode(c.WrapPrivateKeyWithHeaders(true)) + parseResult, _ := x509.ParsePKCS8PrivateKey(block.Bytes) + key := parseResult.(*rsa.PrivateKey) + return key + } + return key +} + +func (c *TSBClient) WrapPrivateKeyWithHeaders(pkcs8 bool) []byte { + if c.Auth.ApplicationKeyPair.PrivateKey == nil { + return nil + } + if pkcs8 == false { + return []byte("-----BEGIN RSA PRIVATE KEY-----\n" + *c.Auth.ApplicationKeyPair.PrivateKey + "\n-----END RSA PRIVATE KEY-----") + } else { + return []byte("-----BEGIN PRIVATE KEY-----\n" + *c.Auth.ApplicationKeyPair.PrivateKey + "\n-----END PRIVATE KEY-----") + + } + +} +func (c *TSBClient) GenerateRequestSignature(requestData string) []byte { + if c.Auth.ApplicationKeyPair.PrivateKey == nil || c.Auth.ApplicationKeyPair.PublicKey == nil { + return []byte("null") + } + dst := &bytes.Buffer{} + if err := json.Compact(dst, []byte(requestData)); err != nil { + panic(err) + } + signature, _ := c.SignData([]byte(dst.String())) + return []byte(`{ + "signature": "` + *signature + `", + "digestAlgorithm": "SHA-256", + "publicKey": "` + *c.Auth.ApplicationKeyPair.PublicKey + `" + } + `) +} +func (c *TSBClient) SignData(dataToSign []byte) (*string, error) { + if c.Auth.ApplicationKeyPair.PrivateKey == nil || c.Auth.ApplicationKeyPair.PublicKey == nil { + return nil, fmt.Errorf("No Application Private Key or Public Key provided!") + } + h := sha256.New() + h.Write(dataToSign) + bs := h.Sum(nil) + signature, err := rsa.SignPKCS1v15(rand.Reader, c.GetApplicationPrivateKey(), crypto.SHA256, bs) + if err != nil { + return nil, err + } + result := b64.StdEncoding.EncodeToString(signature) + return &result, nil +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func (c *TSBClient) PrepareMetaData(requestType string, additionalMetaData map[string]string, customMetaData map[string]string) (string, *string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = c.Auth.AppName + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + for key, value := range customMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", nil, errMarshal + } + result, err := c.SignData(metaJsonStr) + if err != nil { + return b64.StdEncoding.EncodeToString(metaJsonStr), + nil, nil + + } + return b64.StdEncoding.EncodeToString(metaJsonStr), + result, nil +} diff --git a/client/additionalMethods.go b/client/additionalMethods.go new file mode 100644 index 0000000..ebcc97c --- /dev/null +++ b/client/additionalMethods.go @@ -0,0 +1,46 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej, Mikolaj Szargut + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "net/http" + "time" + + helpers "securosys.ch/helpers" +) + +func (c *TSBClient) RemoveKeyAllVersions(key helpers.KeyEntry) error { + for _, version := range key.Versions { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+version.KeyLabel, nil) + c.doRequest(req, KeyManagementTokenName) + } + + return nil + +} +func (c *TSBClient) RemoveKeyVersion(keys map[string]helpers.KeyVersion, version string) error { + time.Sleep(500) + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keys[version].KeyLabel, nil) + c.doRequest(req, KeyManagementTokenName) + + return nil + +} diff --git a/client/block.go b/client/block.go new file mode 100644 index 0000000..a3d24c4 --- /dev/null +++ b/client/block.go @@ -0,0 +1,103 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej, Mikolaj Szargut + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "encoding/json" + "net/http" + + helpers "securosys.ch/helpers" +) + +// Function thats send block request to TSB +func (c *TSBClient) Block(label string, password string) (int, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "blockRequest": { + ` + passwordString + ` + "blockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousBlock", bytes.NewBuffer(jsonStr)) + if err != nil { + return 500, err + } + _, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return code, errRes + } + return code, nil + +} + +// Function thats send asynchronous block request to TSB +func (c *TSBClient) AsyncBlock(label string, password string, customMetaData map[string]string) (string, int, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := c.PrepareMetaData("Block", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", 500, err + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + metaDataSignatureString := "null" + if metaDataSignature != nil { + metaDataSignatureString = `"` + *metaDataSignature + `"` + + } + requestJson := `{ + "blockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": ` + metaDataSignatureString + ` + }` + var jsonStr = []byte(helpers.MinifyJson(`{ + "blockRequest": ` + requestJson + `, + "requestSignature":` + string(c.GenerateRequestSignature(requestJson)) + ` + + }`)) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/block", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return "", code, errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", code, errJSON + } + return result["blockKeyRequestId"].(string), code, nil + +} diff --git a/client/certs.go b/client/certs.go new file mode 100644 index 0000000..3258cda --- /dev/null +++ b/client/certs.go @@ -0,0 +1,446 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej, Mikolaj Szargut + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "strings" + + helpers "securosys.ch/helpers" +) + +// Function thats create a certificate request to TSB +func (c *TSBClient) CreateCertificate(signKeyName string, keyPassword string, signatureAlgorithm string, validity int, certAttributes helpers.CertificateAttributes, keyUsage []string, extendedKeyUsage []string) (*helpers.GenerateCertificateRequestResponse, int, error) { + + var jsonStr []byte + + if keyPassword == "" { + certAttributesJson, _ := json.Marshal(certAttributes) + jsonStr = []byte(`{ + "signKeyName": "` + signKeyName + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "validity": ` + fmt.Sprint(validity) + `, + "standardCertificateAttributes":` + string(certAttributesJson) + `, + "keyUsage": ["` + strings.Join(keyUsage[:], ",") + `"], + "extendedKeyUsage": ["` + strings.Join(extendedKeyUsage[:], ",") + `"] + }`) + + } else { + keyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyPassword)) + certAttributesJson, _ := json.Marshal(certAttributes) + + jsonStr = []byte(`{ + "signKeyName": "` + signKeyName + `", + "keyPassword": ` + string(keyPasswordJson) + `, + "signatureAlgorithm": "` + signatureAlgorithm + `", + "validity": ` + fmt.Sprint(validity) + `, + "standardCertificateAttributes":` + string(certAttributesJson) + `, + "keyUsage": ["` + strings.Join(keyUsage[:], ",") + `"], + "extendedKeyUsage": ["` + strings.Join(extendedKeyUsage[:], ",") + `"] + }`) + } + + req, err := http.NewRequest("POST", c.HostURL+"/v1/certificate/synchronous/request", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return nil, code, errRes + } + var response helpers.GenerateCertificateRequestResponse + // response.KeyID = signKeyName + // response.CertificateRequest = string(body) + json.Unmarshal(body, &response) + return &response, code, nil + +} + +func (c *TSBClient) CreateSelfSignedCertificate(signKeyName string, keyPassword string, signatureAlgorithm string, validity int, commonName string, keyUsage []string, extendedKeyUsage []string, certificateAuthority bool) (*helpers.GenerateSelfSignedCertificateResponse, int, error) { + + var jsonStr []byte + keyUsageJson, _ := json.Marshal(keyUsage) + extendedKeyUsageJson, _ := json.Marshal(extendedKeyUsage) + if keyPassword == "" { + jsonStr = []byte(`{ + "signKeyName": "` + signKeyName + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "validity": ` + fmt.Sprint(validity) + `, + "commonName": "` + commonName + `", + "keyUsage": ` + string(keyUsageJson) + `, + "extendedKeyUsage": ` + string(extendedKeyUsageJson) + `, + "certificateAuthority": ` + fmt.Sprint(certificateAuthority) + ` + }`) + + } else { + keyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyPassword)) + + jsonStr = []byte(`{ + "signKeyName": "` + signKeyName + `", + "keyPassword": ` + string(keyPasswordJson) + `, + "signatureAlgorithm": "` + signatureAlgorithm + `", + "validity": ` + fmt.Sprint(validity) + `, + "commonName": "` + commonName + `", + "keyUsage": ` + string(keyUsageJson) + `, + "extendedKeyUsage": ` + string(extendedKeyUsageJson) + `, + "certificateAuthority": ` + fmt.Sprint(certificateAuthority) + ` + }`) + } + req, err := http.NewRequest("POST", c.HostURL+"/v1/certificate/synchronous/selfsign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return nil, code, errRes + } + var response helpers.GenerateSelfSignedCertificateResponse + // response.KeyID = signKeyName + // response.CertificateRequest = string(body) + json.Unmarshal(body, &response) + return &response, code, nil + +} + +func (c *TSBClient) SignCertificate(signKeyName string, keyPassword string, signatureAlgorithm string, certificateSigningRequest string, commonName string, keyUsage []string, extendedKeyUsage []string, certificateAuthority bool) (*helpers.GenerateSelfSignedCertificateResponse, int, error) { + + var jsonStr []byte + if keyPassword == "" { + + jsonStr = []byte(`{ + "signKeyName": "` + signKeyName + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "commonName": "` + commonName + `", + "certificateSigningRequest": "` + certificateSigningRequest + `", + "keyUsage": ["` + strings.Join(keyUsage[:], ",") + `"], + "extendedKeyUsage": ["` + strings.Join(extendedKeyUsage[:], ",") + `"], + "certificateAuthority": ` + fmt.Sprint(certificateAuthority) + ` + + }`) + + } else { + keyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyPassword)) + + jsonStr = []byte(`{ + "signKeyName": "` + signKeyName + `", + "keyPassword": ` + string(keyPasswordJson) + `, + "signatureAlgorithm": "` + signatureAlgorithm + `", + "commonName": "` + commonName + `", + "certificateSigningRequest": "` + certificateSigningRequest + `", + "keyUsage": ["` + strings.Join(keyUsage[:], ",") + `"], + "extendedKeyUsage": ["` + strings.Join(extendedKeyUsage[:], ",") + `"], + "certificateAuthority": ` + fmt.Sprint(certificateAuthority) + ` + }`) + } + + req, err := http.NewRequest("POST", c.HostURL+"/v1/certificate/synchronous/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return nil, code, errRes + } + var response helpers.GenerateSelfSignedCertificateResponse + // response.KeyID = signKeyName + // response.CertificateRequest = string(body) + json.Unmarshal(body, &response) + return &response, code, nil + +} + +// Function thats create a certificate request to TSB +func (c *TSBClient) AsyncCreateCertificate(signKeyName string, keyPassword string, signatureAlgorithm string, validity int, certAttributes helpers.CertificateAttributes, keyUsage []string, extendedKeyUsage []string, userMetaData map[string]string) (string, int, error) { + + var jsonStr []byte + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["certificate attributes"] = certAttributes.ToString() + additionalMetaDataInfo["key usage"] = strings.Join(keyUsage[:], ",") + additionalMetaDataInfo["validity"] = fmt.Sprintf("%d days", validity) + additionalMetaDataInfo["extended key usage"] = strings.Join(extendedKeyUsage[:], ",") + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + for index, value := range userMetaData { + additionalMetaDataInfo[index] = value + } + + metaDataB64, metaDataSignature, _ := c.PrepareMetaData("CertificateSigningRequest", additionalMetaDataInfo, map[string]string{}) + metaDataSignatureString := "null" + if metaDataSignature != nil { + metaDataSignatureString = `"` + *metaDataSignature + `"` + + } + + if keyPassword == "" { + certAttributesJson, _ := json.Marshal(certAttributes) + requestJson := `{ + "signKeyName": "` + signKeyName + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "validity": ` + fmt.Sprint(validity) + `, + "standardCertificateAttributes":` + string(certAttributesJson) + `, + "keyUsage": ["` + strings.Join(keyUsage[:], ",") + `"], + "extendedKeyUsage": ["` + strings.Join(extendedKeyUsage[:], ",") + `"], + "metaData": "` + metaDataB64 + `", + "metaDataSignature": ` + metaDataSignatureString + ` + }` + jsonStr = []byte(helpers.MinifyJson(`{ + "csrSignRequest": ` + requestJson + ` , + "requestSignature":` + string(c.GenerateRequestSignature(requestJson)) + `}`)) + + } else { + keyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyPassword)) + certAttributesJson, _ := json.Marshal(certAttributes) + requestJson := `{ + "signKeyName": "` + signKeyName + `", + "keyPassword": ` + string(keyPasswordJson) + `, + "signatureAlgorithm": "` + signatureAlgorithm + `", + "validity": ` + fmt.Sprint(validity) + `, + "standardCertificateAttributes":` + string(certAttributesJson) + `, + "keyUsage": ["` + strings.Join(keyUsage[:], ",") + `"], + "extendedKeyUsage": ["` + strings.Join(extendedKeyUsage[:], ",") + `"], + "metaData": "` + metaDataB64 + `", + "metaDataSignature": ` + metaDataSignatureString + ` + }` + jsonStr = []byte(helpers.MinifyJson(`{ + "csrSignRequest": ` + requestJson + `, + "requestSignature":` + string(c.GenerateRequestSignature(requestJson)) + `}`)) + } + + req, err := http.NewRequest("POST", c.HostURL+"/v1/certificate/request", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return "", code, errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", code, errJSON + } + return result["signRequestId"].(string), code, nil + +} + +func (c *TSBClient) AsyncSelfSignedCertificate(signKeyName string, keyPassword string, signatureAlgorithm string, validity int, commonName string, keyUsage []string, extendedKeyUsage []string, certificateAuthority bool, userMetaData map[string]string) (string, int, error) { + + var jsonStr []byte + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["common name"] = commonName + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + additionalMetaDataInfo["key usage"] = strings.Join(keyUsage[:], ", ") + additionalMetaDataInfo["extended key usage"] = strings.Join(extendedKeyUsage[:], ", ") + additionalMetaDataInfo["validity"] = fmt.Sprintf("%d days", validity) + + for index, value := range userMetaData { + additionalMetaDataInfo[index] = value + } + + metaDataB64, metaDataSignature, _ := c.PrepareMetaData("SelfSignCertificate", additionalMetaDataInfo, map[string]string{}) + metaDataSignatureString := "null" + if metaDataSignature != nil { + metaDataSignatureString = `"` + *metaDataSignature + `"` + + } + + if keyPassword == "" { + requestJson := `{ + "signKeyName": "` + signKeyName + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "validity": ` + fmt.Sprint(validity) + `, + "commonName": "` + commonName + `", + "keyUsage": ["` + strings.Join(keyUsage[:], ",") + `"], + "extendedKeyUsage": ["` + strings.Join(extendedKeyUsage[:], ", ") + `"], + "metaData": "` + metaDataB64 + `", + "metaDataSignature": ` + metaDataSignatureString + `, + "certificateAuthority": ` + fmt.Sprint(certificateAuthority) + ` + }` + jsonStr = []byte(helpers.MinifyJson(`{ + "selfSignCertificateRequest":` + requestJson + `, + "requestSignature":` + string(c.GenerateRequestSignature(requestJson)) + `}`)) + + } else { + keyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyPassword)) + requestJson := `{ + "signKeyName": "` + signKeyName + `", + "keyPassword": ` + string(keyPasswordJson) + `, + "signatureAlgorithm": "` + signatureAlgorithm + `", + "validity": ` + fmt.Sprint(validity) + `, + "commonName": "` + commonName + `", + "keyUsage": ["` + strings.Join(keyUsage[:], ",") + `"], + "extendedKeyUsage": ["` + strings.Join(extendedKeyUsage[:], ", ") + `"], + "metaData": "` + metaDataB64 + `", + "metaDataSignature": ` + metaDataSignatureString + `, + "certificateAuthority": ` + fmt.Sprint(certificateAuthority) + ` + }` + jsonStr = []byte(helpers.MinifyJson(`{ + "selfSignCertificateRequest":` + requestJson + `, + "requestSignature":` + string(c.GenerateRequestSignature(requestJson)) + `}`)) + } + + req, err := http.NewRequest("POST", c.HostURL+"/v1/certificate/selfsign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return "", code, errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", code, errJSON + } + return result["signRequestId"].(string), code, nil + +} + +func (c *TSBClient) AsyncSignCertificate(signKeyName string, keyPassword string, signatureAlgorithm string, certificateSigningRequest string, commonName string, keyUsage []string, extendedKeyUsage []string, certificateAuthority bool, userMetaData map[string]string) (string, int, error) { + + var jsonStr []byte + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["common name"] = commonName + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + additionalMetaDataInfo["key usage"] = strings.Join(keyUsage[:], ", ") + additionalMetaDataInfo["extended key usage"] = strings.Join(extendedKeyUsage[:], ", ") + + for index, value := range userMetaData { + additionalMetaDataInfo[index] = value + } + + metaDataB64, metaDataSignature, _ := c.PrepareMetaData("Certificate", additionalMetaDataInfo, map[string]string{}) + metaDataSignatureString := "null" + if metaDataSignature != nil { + metaDataSignatureString = `"` + *metaDataSignature + `"` + + } + + if keyPassword == "" { + requestJson := `{ + "signKeyName": "` + signKeyName + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "commonName": "` + commonName + `", + "certificateSigningRequest": "` + certificateSigningRequest + `", + "keyUsage": ["` + strings.Join(keyUsage[:], ",") + `"], + "extendedKeyUsage": ["` + strings.Join(extendedKeyUsage[:], ",") + `"], + "metaData": "` + metaDataB64 + `", + "metaDataSignature": ` + metaDataSignatureString + `, + "certificateAuthority": ` + fmt.Sprint(certificateAuthority) + ` + + }` + jsonStr = []byte(helpers.MinifyJson(`{ + "signCertificateRequest": ` + requestJson + `, + "requestSignature":` + string(c.GenerateRequestSignature(requestJson)) + ` + }`)) + + } else { + keyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyPassword)) + requestJson := `{ + "signKeyName": "` + signKeyName + `", + "keyPassword": ` + string(keyPasswordJson) + `, + "signatureAlgorithm": "` + signatureAlgorithm + `", + "commonName": "` + commonName + `", + "certificateSigningRequest": "` + certificateSigningRequest + `", + "keyUsage": ["` + strings.Join(keyUsage[:], ",") + `"], + "extendedKeyUsage": ["` + strings.Join(extendedKeyUsage[:], ",") + `"], + "metaData": "` + metaDataB64 + `", + "metaDataSignature": ` + metaDataSignatureString + `, + "certificateAuthority": ` + fmt.Sprint(certificateAuthority) + ` + }` + jsonStr = []byte(helpers.MinifyJson(`{ + "signCertificateRequest": ` + requestJson + `, + "requestSignature":` + string(c.GenerateRequestSignature(requestJson)) + `}`)) + } + + req, err := http.NewRequest("POST", c.HostURL+"/v1/certificate/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return "", code, errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", code, errJSON + } + return result["signRequestId"].(string), code, nil + +} + +// Function thats import a certificate request from TSB +func (c *TSBClient) ImportCertificate(label string, certificate string) (*helpers.RequestResponseImportCertificate, int, error) { + + var jsonStr = []byte(`{ + "label": "` + label + `", + "certificate": "` + certificate + `", + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/certificate/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return nil, code, errRes + } + var response helpers.RequestResponseImportCertificate + json.Unmarshal(body, &response) + return &response, code, nil + +} + +// Function thats sends get request to TSB +func (c *TSBClient) GetCertificate(label string) (*helpers.RequestResponseCertificate, int, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/certificate/"+label, bytes.NewBuffer(nil)) + if err != nil { + return nil, 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return nil, code, errRes + } + var requestResponse helpers.RequestResponseCertificate + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, code, errJSON + } + + return &requestResponse, code, nil +} + +// Function thats delete certificate TSB +func (c *TSBClient) DeleteCertificate(label string) (int, error) { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/certificate/"+label, nil) + if err != nil { + return 500, err + } + _, code, errReq := c.doRequest(req, KeyOperationTokenName) + if errReq != nil { + return code, errReq + } + return code, nil +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..f811e4a --- /dev/null +++ b/client/client.go @@ -0,0 +1,64 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "encoding/json" + "errors" + + helpers "securosys.ch/helpers" +) + +// securosysClient creates an object storing +// the client. +type SecurosysClient struct { + *TSBClient +} + +// newClient creates a new client to access HashiCups +func NewClient(config *helpers.SecurosysConfig) (*SecurosysClient, error) { + if config == nil { + return nil, errors.New("client configuration was nil") + } + bytes, _ := json.Marshal(config) + var mappedConfig map[string]string + json.Unmarshal(bytes, &mappedConfig) + var keyPair KeyPair + json.Unmarshal([]byte(mappedConfig["applicationKeyPair"]), &keyPair) + + var apiKeys ApiKeyTypes + json.Unmarshal([]byte(mappedConfig["apiKeys"]), &apiKeys) + c, err := NewTSBClient(mappedConfig["restapi"], AuthStruct{ + AuthType: mappedConfig["auth"], + CertPath: mappedConfig["certpath"], + KeyPath: mappedConfig["keypath"], + BearerToken: mappedConfig["bearertoken"], + BasicToken: mappedConfig["basictoken"], + Username: mappedConfig["username"], + Password: mappedConfig["password"], + ApplicationKeyPair: keyPair, + ApiKeys: apiKeys, + AppName: "HCVault Plugin Secrets Engine", + }) + if err != nil { + return nil, err + } + return &SecurosysClient{c}, nil +} diff --git a/client/encrypt.go b/client/encrypt.go new file mode 100644 index 0000000..e0cf4c0 --- /dev/null +++ b/client/encrypt.go @@ -0,0 +1,193 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej, Mikolaj Szargut + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "encoding/json" + "net/http" + "strconv" + + helpers "securosys.ch/helpers" +) + +// Function thats sends asynchronous decrypt request to TSB +func (c *TSBClient) AsyncDecrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string, customMetaData map[string]string) (string, int, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["encrypted payload"] = cipertext + additionalMetaDataInfo["cipher algorithm"] = cipherAlgorithm + additionalMetaDataInfo["tag length"] = strconv.Itoa(tagLength) + additionalMetaDataInfo["additional authentication data"] = additionalAuthenticationData + additionalMetaDataInfo["initialization vector"] = vector + + metaDataB64, metaDataSignature, err := c.PrepareMetaData("Decrypt", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", 500, err + } + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + metaDataSignatureString := "null" + if metaDataSignature != nil { + metaDataSignatureString = `"` + *metaDataSignature + `"` + + } + requestJson := `{ + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": ` + metaDataSignatureString + `, + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + }` + + var jsonStr = []byte(helpers.MinifyJson(`{ + "decryptRequest": ` + helpers.MinifyJson(requestJson) + `, + "requestSignature":` + string(c.GenerateRequestSignature(requestJson)) + ` + }`)) + req, err := http.NewRequest("POST", c.HostURL+"/v1/decrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return "", code, errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", code, errJSON + } + return result["decryptRequestId"].(string), code, nil + // return response, nil + +} + +// Function thats sends decrypt request to TSB +func (c *TSBClient) Decrypt(label string, password string, cipertext string, vector string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (*helpers.DecryptResponse, int, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + vectorString := `"` + vector + `"` + if vector == "" { + vectorString = "null" + } + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "decryptRequest": { + "encryptedPayload": "` + cipertext + `", + ` + passwordString + ` + "decryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + "initializationVector": ` + vectorString + `, + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousDecrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return nil, code, errRes + } + var decryptResponse helpers.DecryptResponse + errJSON := json.Unmarshal(body, &decryptResponse) + if errJSON != nil { + return nil, code, errJSON + } + return &decryptResponse, code, nil + +} + +// Function thats send encrypt request to TSB +func (c *TSBClient) Encrypt(label string, password string, payload string, cipherAlgorithm string, tagLength int, additionalAuthenticationData string) (*helpers.EncryptResponse, int, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + additionalAuthenticationDataString := `"` + additionalAuthenticationData + `"` + if additionalAuthenticationData == "" { + additionalAuthenticationDataString = "null" + } + tagLengthString := "" + if tagLength != -1 && cipherAlgorithm == "AES_GSM" { + tagLengthString = `"tagLength":` + strconv.Itoa(tagLength) + `,` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "encryptRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "encryptKeyName": "` + label + `", + "cipherAlgorithm": "` + cipherAlgorithm + `", + ` + tagLengthString + ` + "additionalAuthenticationData":` + additionalAuthenticationDataString + ` + } + }`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/encrypt", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return nil, code, errRes + } + var encryptResponse helpers.EncryptResponse + errJSON := json.Unmarshal(body, &encryptResponse) + if errJSON != nil { + return nil, code, errJSON + } + return &encryptResponse, code, nil + +} diff --git a/client/go.mod b/client/go.mod new file mode 100644 index 0000000..d9ad604 --- /dev/null +++ b/client/go.mod @@ -0,0 +1,46 @@ +module securosys.ch/client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require securosys.ch/helpers v0.0.0-00010101000000-000000000000 + +require ( + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/vault/sdk v0.9.1 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/client/go.sum b/client/go.sum new file mode 100644 index 0000000..20a0ffc --- /dev/null +++ b/client/go.sum @@ -0,0 +1,203 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/client/go.work b/client/go.work new file mode 100644 index 0000000..c4b66c9 --- /dev/null +++ b/client/go.work @@ -0,0 +1,6 @@ +go 1.20 + +use ( + ./ + ./helpers +) \ No newline at end of file diff --git a/client/go.work.sum b/client/go.work.sum new file mode 100644 index 0000000..5201595 --- /dev/null +++ b/client/go.work.sum @@ -0,0 +1 @@ +git.securosys.ch/application/tsb-client-go/helpers v0.0.0-20240110135900-db05d8af6606/go.mod h1:hOtCFe2d+Y2vR2b3ArLaIa2x+eOyZk4CBDL4s/b62ZY= diff --git a/client/health.go b/client/health.go new file mode 100644 index 0000000..8b7b5b5 --- /dev/null +++ b/client/health.go @@ -0,0 +1,35 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej, Mikolaj Szargut + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import "net/http" + +func (c *TSBClient) CheckConnection() (string, int, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/keystore/statistics", nil) + if err != nil { + return "", 500, err + } + body, code, errReq := c.doRequest(req, ServiceTokenName) + if errReq != nil { + return string(body[:]), code, errReq + } + return string(body[:]), code, nil + +} diff --git a/client/key.go b/client/key.go new file mode 100644 index 0000000..d0c9c4f --- /dev/null +++ b/client/key.go @@ -0,0 +1,256 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej, Mikolaj Szargut + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + + helpers "securosys.ch/helpers" +) + +// Function thats sends update key password request to TSB +func (c *TSBClient) UpdateKeyPassword(label string, password string, newPassword string) (string, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + charsNewPasswordJson, _ := json.Marshal(helpers.StringToCharArray(newPassword)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + newPasswordString := "" + if len(charsNewPasswordJson) > 2 { + newPasswordString = `"newPassword": ` + string(charsNewPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + newPasswordString + ` + "label": "` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/changePassword", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + _, _, errRes := c.doRequest(req, KeyManagementTokenName) + if errRes != nil { + return "", errRes + } + return label, nil + +} + +// Function thats sends create key request to TSB +func (c *TSBClient) CreateOrUpdateKey(label string, password string, attributes map[string]bool, keytype string, keySize float64, policy *helpers.Policy, curveOid string, modify bool) (string, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + policyJson, _ := json.Marshal(&policy) + policyString := string(`,"policy":` + string(policyJson)) + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + var keySizeAttr string + if keySize == 0 { + keySizeAttr = "" + } else { + keySizeAttr = `"keySize": ` + fmt.Sprintf("%g", keySize) + `,` + } + var curveOidString string + if curveOid == "" { + curveOidString = "" + } else { + curveOidString = `"curveOid": "` + curveOid + `",` + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + passwordString + ` + ` + keySizeAttr + ` + ` + curveOidString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", err + } + body, _, err := c.doRequest(req, KeyManagementTokenName) + if err != nil { + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", errJSON + } + return "", err + } + return label, nil +} + +// Function thats sends delete key request to TSB +func (c *TSBClient) RemoveKey(keyLabel string) error { + req, _ := http.NewRequest("DELETE", c.HostURL+"/v1/key/"+keyLabel, nil) + c.doRequest(req, KeyManagementTokenName) + return nil + +} + +// Function thats sends import key request to TSB +func (c *TSBClient) ImportKey(label string, privateKey string, publicKey string, secretKey string, certificate string, attributes map[string]bool, keytype string, policy helpers.Policy) (map[string]interface{}, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + var privateKeyString string + if privateKey == "" { + privateKeyString = "" + } else { + privateKeyString = `"privateKey": "` + privateKey + `",` + } + var publicKeyString string + if publicKey == "" { + publicKeyString = "" + } else { + publicKeyString = `"publicKey": "` + publicKey + `",` + } + var secretKeyString string + if secretKey == "" { + secretKeyString = "" + } else { + secretKeyString = `"secretKey": "` + secretKey + `",` + } + var certificateString string + if certificate == "" { + certificateString = "" + } else { + certificateString = `"certificate": "` + certificate + `",` + } + var jsonStr = []byte(`{ + "label": "` + label + `", + "algorithm": "` + keytype + `", + ` + privateKeyString + ` + ` + publicKeyString + ` + ` + secretKeyString + ` + ` + certificateString + ` + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + `}`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/import/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, _, errRes := c.doRequest(req, KeyManagementTokenName) + if errRes != nil { + return nil, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + return response, nil + +} + +// Function thats sends export request to TSB +func (c *TSBClient) ExportKey(label string, password string) (map[string]interface{}, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + ` + passwordString + ` + "label": "` + label + `" + + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/export/plain", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + body, _, errRes := c.doRequest(req, KeyManagementTokenName) + if errRes != nil { + return nil, errRes + } + + var response map[string]interface{} + json.Unmarshal(body, &response) + + return response, nil + +} + +// Function thats sends get key attribute request to TSB +func (c *TSBClient) GetKey(label string, password string) (helpers.KeyAttributes, error) { + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"password": ` + string(charsPasswordJson) + `,` + + } + var jsonStr = []byte(`{ + ` + passwordString + ` + "label":"` + label + `" + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/key/attributes", bytes.NewBuffer(jsonStr)) + var key helpers.KeyAttributes + if err != nil { + return key, err + } + body, _, errRes := c.doRequest(req, KeyManagementTokenName) + if errRes != nil { + return key, errRes + } + var response interface{} + json.Unmarshal(body, &response) + data := response.(map[string]interface{}) + jsonData := data["json"].(map[string]interface{}) + key.Algorithm = jsonData["algorithm"].(string) + key.AlgorithmOid = jsonData["algorithmOid"].(string) + key.CurveOid = "" + if fmt.Sprintf("%T", jsonData["curveOid"]) == "string" { + key.CurveOid = jsonData["curveOid"].(string) + } + key.Attributes = map[string]bool{} + attributes := jsonData["attributes"].(map[string]interface{}) + for k, e := range attributes { + if fmt.Sprintf("%T", e) == "bool" { + key.Attributes[k] = e.(bool) + } + } + if fmt.Sprintf("%T", jsonData["keySize"]) == "float64" { + key.KeySize = jsonData["keySize"].(float64) + } + key.Xml = data["xml"].(string) + key.XmlSignature = data["xmlSignature"].(string) + key.AttestationKeyName = data["attestationKeyName"].(string) + key.Label = jsonData["label"].(string) + policyString, _ := json.Marshal(jsonData["policy"]) + json.Unmarshal(policyString, &key.Policy) + if fmt.Sprintf("%T", jsonData["publicKey"]) == "string" { + key.PublicKey = jsonData["publicKey"].(string) + } + return key, nil + +} diff --git a/client/modify.go b/client/modify.go new file mode 100644 index 0000000..7046ac5 --- /dev/null +++ b/client/modify.go @@ -0,0 +1,106 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej, Mikolaj Szargut + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "encoding/json" + "net/http" + + helpers "securosys.ch/helpers" +) + +// Function thats send request modify key to TSB +func (c *TSBClient) Modify(label string, password string, policy helpers.Policy) (int, error) { + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "modifyRequest":{ + ` + passwordString + ` + "modifyKeyName": "` + label + `" + ` + policyString + `} + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousModify", bytes.NewBuffer(jsonStr)) + if err != nil { + return 500, err + } + _, code, errRes := c.doRequest(req, KeyManagementTokenName) + if errRes != nil { + return code, errRes + } + return code, nil + +} + +// Function thats send asynchronous request modify key to TSB +func (c *TSBClient) AsyncModify(label string, password string, policy helpers.Policy, customMetaData map[string]string) (string, int, error) { + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := c.PrepareMetaData("Modify", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", 500, err + } + policyJson, _ := json.Marshal(policy) + policyString := string(`,"policy":` + string(policyJson)) + + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + metaDataSignatureString := "null" + if metaDataSignature != nil { + metaDataSignatureString = `"` + *metaDataSignature + `"` + + } + requestJson := `{"modifyKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": ` + metaDataSignatureString + ` + ` + policyString + `}` + var jsonStr = []byte(helpers.MinifyJson(`{ + "modifyRequest":` + requestJson + `, + "requestSignature":` + string(c.GenerateRequestSignature(requestJson)) + ` + }`)) + req, err := http.NewRequest("POST", c.HostURL+"/v1/modify", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", 500, err + } + body, code, errRes := c.doRequest(req, KeyManagementTokenName) + if errRes != nil { + return "", code, errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", code, errJSON + } + return result["modifyKeyRequestId"].(string), code, nil + +} diff --git a/client/requests.go b/client/requests.go new file mode 100644 index 0000000..bade261 --- /dev/null +++ b/client/requests.go @@ -0,0 +1,63 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej, Mikolaj Szargut + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "encoding/json" + "net/http" + + helpers "securosys.ch/helpers" +) + +// Function thats sends get request to TSB +func (c *TSBClient) GetRequest(id string) (*helpers.RequestResponse, int, error) { + req, err := http.NewRequest("GET", c.HostURL+"/v1/request/"+id, bytes.NewBuffer(nil)) + if err != nil { + return nil, 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return nil, code, errRes + } + var requestResponse helpers.RequestResponse + errJSON := json.Unmarshal(body, &requestResponse) + if errJSON != nil { + return nil, code, errJSON + } + return &requestResponse, code, nil +} + +// Function thats sends delete request to TSB +func (c *TSBClient) RemoveRequest(id string) (int, error) { + req, err := http.NewRequest("DELETE", c.HostURL+"/v1/request/"+id, nil) + if err != nil { + return 500, err + } + _, code, errReq := c.doRequest(req, KeyOperationTokenName) + if code == 404 || code == 500 { + return code, nil + } + if errReq != nil { + return code, errReq + } + return code, nil + +} diff --git a/client/sign.go b/client/sign.go new file mode 100644 index 0000000..197857a --- /dev/null +++ b/client/sign.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej, Mikolaj Szargut + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + + helpers "securosys.ch/helpers" +) + +// Function thats sends sign request to TSB +func (c *TSBClient) Sign(label string, password string, payload string, payloadType string, signatureAlgorithm string) (*helpers.SignatureResponse, int, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "signRequest": { + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousSign", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return nil, code, errRes + } + var response helpers.SignatureResponse + // response.KeyID = signKeyName + // response.CertificateRequest = string(body) + json.Unmarshal(body, &response) + return &response, code, nil + +} + +// Function thats sends asynchronous sign request to TSB +func (c *TSBClient) AsyncSign(label string, password string, payload string, payloadType string, signatureAlgorithm string, customMetaData map[string]string) (string, int, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["payload"] = payload + additionalMetaDataInfo["payload type"] = payloadType + additionalMetaDataInfo["signature algorithm"] = signatureAlgorithm + + metaDataB64, metaDataSignature, err := c.PrepareMetaData("Sign", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", 500, err + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + metaDataSignatureString := "null" + if metaDataSignature != nil { + metaDataSignatureString = `"` + *metaDataSignature + `"` + + } + requestJson := `{ + "payload": "` + payload + `", + "payloadType": "` + payloadType + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "metaData": "` + metaDataB64 + `", + "metaDataSignature": ` + metaDataSignatureString + ` + }` + var jsonStr = []byte(helpers.MinifyJson(`{ + "signRequest": ` + requestJson + `, + "requestSignature":` + string(c.GenerateRequestSignature(requestJson)) + ` + }`)) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/sign", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return "", code, errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", code, errJSON + } + return result["signRequestId"].(string), code, nil + +} + +// Function thats sends verify request to TSB +func (c *TSBClient) Verify(label string, password string, payload string, signatureAlgorithm string, signature string) (bool, int, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"masterKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "verifySignatureRequest": { + "payload": "` + payload + `", + ` + passwordString + ` + "signKeyName": "` + label + `", + "signatureAlgorithm": "` + signatureAlgorithm + `", + "signature": "` + signature + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/verify", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return false, code, errRes + } + var response map[string]interface{} + json.Unmarshal(body, &response) + if !helpers.ContainsKey(response, "signatureValid") { + return false, 500, fmt.Errorf("error on verify response, need signatureValid, found %s", string(body[:])) + } + return response["signatureValid"].(bool), code, nil + +} diff --git a/client/unblock.go b/client/unblock.go new file mode 100644 index 0000000..40a3f87 --- /dev/null +++ b/client/unblock.go @@ -0,0 +1,101 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej, Mikolaj Szargut + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "encoding/json" + "net/http" + + helpers "securosys.ch/helpers" +) + +// Function thats send unblock request to TSB +func (c *TSBClient) UnBlock(label string, password string) (int, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unblockRequest": { + ` + passwordString + ` + "unblockKeyName": "` + label + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return 500, err + } + _, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return code, errRes + } + return code, nil + +} + +// Function thats send asynchronous unblock request to TSB +func (c *TSBClient) AsyncUnBlock(label string, password string, customMetaData map[string]string) (string, int, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(password)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + metaDataB64, metaDataSignature, err := c.PrepareMetaData("UnBlock", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", 500, err + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"keyPassword": ` + string(charsPasswordJson) + `,` + + } + metaDataSignatureString := "null" + if metaDataSignature != nil { + metaDataSignatureString = `"` + *metaDataSignature + `"` + + } + requestJson := `{ + "unblockKeyName": "` + label + `", + ` + passwordString + ` + "metaData": "` + metaDataB64 + `", + "metaDataSignature": ` + metaDataSignatureString + ` + }` + var jsonStr = []byte(helpers.MinifyJson(`{ + "unblockRequest": ` + requestJson + `, + "requestSignature":` + string(c.GenerateRequestSignature(requestJson)) + ` + }`)) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/unblock", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return "", code, errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", code, errJSON + } + return result["unblockKeyRequestId"].(string), code, nil +} diff --git a/client/wrap.go b/client/wrap.go new file mode 100644 index 0000000..57139c1 --- /dev/null +++ b/client/wrap.go @@ -0,0 +1,171 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej, Mikolaj Szargut + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package client + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + + helpers "securosys.ch/helpers" +) + +// Function thats send wrap request to TSB +func (c *TSBClient) Wrap(wrapKeyName string, wrapKeyPassword string, keyToBeWrapped string, keyToBeWrappedPassword string, wrapMethod string) (*helpers.WrapResponse, int, error) { + keyToBeWrappedPasswordJson, _ := json.Marshal(helpers.StringToCharArray(keyToBeWrappedPassword)) + wrapKeyPasswordJson, _ := json.Marshal(helpers.StringToCharArray(wrapKeyPassword)) + keyToBeWrappedPasswordString := "" + if len(keyToBeWrappedPasswordJson) > 2 { + keyToBeWrappedPasswordString = `"keyToBeWrappedPassword": ` + string(keyToBeWrappedPasswordJson) + `,` + + } + wrapKeyPasswordString := "" + if len(wrapKeyPasswordJson) > 2 { + wrapKeyPasswordString = `"wrapKeyPassword": ` + string(wrapKeyPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "wrapKeyRequest": { + "keyToBeWrapped": "` + keyToBeWrapped + `", + ` + keyToBeWrappedPasswordString + ` + "wrapKeyName": "` + wrapKeyName + `", + ` + wrapKeyPasswordString + ` + "wrapMethod":"` + wrapMethod + `" + } + }`) + + req, err := http.NewRequest("POST", c.HostURL+"/v1/wrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return nil, code, errRes + } + var response helpers.WrapResponse + // response.KeyID = signKeyName + // response.CertificateRequest = string(body) + json.Unmarshal(body, &response) + return &response, code, nil + +} + +// Function thats sends asynchronous unwrap request to TSB +func (c *TSBClient) AsyncUnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy, customMetaData map[string]string) (string, int, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var additionalMetaDataInfo map[string]string = make(map[string]string) + additionalMetaDataInfo["wrapped key"] = wrappedKey + additionalMetaDataInfo["new key label"] = label + additionalMetaDataInfo["wrap method"] = wrapMethod + additionalMetaDataInfo["attributes"] = fmt.Sprintf("%v", attributes) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(*policy) + policyString = string(`,"policy":` + string(policyJson)) + } + + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + //Only for asychronous unwrap + policyString = string(``) + metaDataB64, metaDataSignature, err := c.PrepareMetaData("UnWrap", additionalMetaDataInfo, customMetaData) + if err != nil { + return "", 500, err + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + metaDataSignatureString := "null" + if metaDataSignature != nil { + metaDataSignatureString = `"` + *metaDataSignature + `"` + + } + requestJson := `{ + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + `, + "metaData": "` + metaDataB64 + `", + "metaDataSignature": ` + metaDataSignatureString + `` + policyString + ` + }` + var jsonStr = []byte(helpers.MinifyJson(`{ + "unwrapKeyRequest": ` + requestJson + `, + "requestSignature":` + string(c.GenerateRequestSignature(requestJson)) + ` + }`)) + req, err := http.NewRequest("POST", c.HostURL+"/v1/unwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return "", 500, err + } + body, code, errRes := c.doRequest(req, KeyOperationTokenName) + if errRes != nil { + return "", code, errRes + } + var result map[string]interface{} + errJSON := json.Unmarshal(body, &result) + if errJSON != nil { + return "", code, errJSON + } + return result["unwrapRequestId"].(string), code, nil +} + +// Function thats sends unwrap request to TSB +func (c *TSBClient) UnWrap(wrappedKey string, label string, attributes map[string]bool, unwrapKeyName string, unwrapKeyPassword string, wrapMethod string, policy *helpers.Policy) (int, error) { + charsPasswordJson, _ := json.Marshal(helpers.StringToCharArray(unwrapKeyPassword)) + var policyString string + if policy == nil { + policyString = string(`,"policy":null`) + } else { + policyJson, _ := json.Marshal(policy) + policyString = string(`,"policy":` + string(policyJson)) + } + if attributes["extractable"] { + policyString = string(`,"policy":null`) + } + passwordString := "" + if len(charsPasswordJson) > 2 { + passwordString = `"unwrapKeyPassword": ` + string(charsPasswordJson) + `,` + + } + + var jsonStr = []byte(`{ + "unwrapKeyRequest": { + "wrappedKey": "` + wrappedKey + `", + "label": "` + label + `", + "unwrapKeyName": "` + unwrapKeyName + `", + ` + passwordString + ` + "wrapMethod": "` + wrapMethod + `", + "attributes": ` + helpers.PrepareAttributes(attributes) + policyString + ` + }}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/synchronousUnwrap", bytes.NewBuffer(jsonStr)) + if err != nil { + return 500, err + } + _, code, err := c.doRequest(req, KeyOperationTokenName) + return code, err +} diff --git a/cmd/securosys-hsm/main.go b/cmd/securosys-hsm/main.go new file mode 100644 index 0000000..61d17be --- /dev/null +++ b/cmd/securosys-hsm/main.go @@ -0,0 +1,49 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package main + +import ( + "os" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/api" + "github.com/hashicorp/vault/sdk/plugin" + backend "securosys.ch/backend" +) + +func main() { + apiClientMeta := &api.PluginAPIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(os.Args[1:]) + + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) + + err := plugin.Serve(&plugin.ServeOpts{ + BackendFactoryFunc: backend.Factory, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + logger := hclog.New(&hclog.LoggerOptions{}) + + logger.Error("plugin shutting down", "error", err) + os.Exit(1) + } +} diff --git a/docker-builder/alpine3/docker-compose-alpine3.yml b/docker-builder/alpine3/docker-compose-alpine3.yml new file mode 100644 index 0000000..1190d88 --- /dev/null +++ b/docker-builder/alpine3/docker-compose-alpine3.yml @@ -0,0 +1,56 @@ + version: "3.3" + services: + golang-builder-alpine3-amd64: + platform: linux/amd64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=amd64 + image: amd64/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-amd64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-i386: + platform: linux/i386 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=386 + image: i386/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-i386 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" + golang-builder-alpine3-arm64: + platform: linux/arm64 + environment: + - DOCKER_OS=alpine3 + - DOCKER_ARCH=arm64 + image: arm64v8/golang:1.21.3-alpine3.18 + container_name: golang-alpine3-arm64 + restart: always + + volumes: + - ./../:/docker-scripts # place for application configuration files + - ./../../:/src # place for application configuration files + command: sh -c "sleep 1s && + apk update && + apk add zip && + apk add perl-utils && + cd /docker-scripts && + sh build-in-docker.sh" \ No newline at end of file diff --git a/docker-builder/build-in-docker.sh b/docker-builder/build-in-docker.sh new file mode 100644 index 0000000..adc15b2 --- /dev/null +++ b/docker-builder/build-in-docker.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd .. +echo "Build ${ARTIFACT_NAME} in ${DOCKER_OS}_${DOCKER_ARCH}"; + cd /src + CGO_ENABLED=0 go build -o builds/securosys-hsm cmd/securosys-hsm/main.go; + cd builds; + shasum -a 256 securosys-hsm > securosys-hsm_SHA256SUM; + zip -9 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip securosys-hsm securosys-hsm_SHA256SUM; + shasum -a 256 ${ARTIFACT_NAME}_${DOCKER_OS}_${DOCKER_ARCH}.zip >> ${ARTIFACT_NAME}_SHA256SUMS; + cd ..; + rm builds/securosys-hsm; + rm builds/securosys-hsm_SHA256SUM; \ No newline at end of file diff --git a/etc/example/mariaDb.cfg b/etc/example/mariaDb.cfg new file mode 100644 index 0000000..298e73a --- /dev/null +++ b/etc/example/mariaDb.cfg @@ -0,0 +1,22 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="{vault_address}/v1/securosys-hsm/integrations/mariadb/{secret_name}/?key_name={key-name}&cipher_algorithm={cipher_algorithm}&tag_length={tag_length}&aad={additional_authentication_data}&password={password}&version=" +loose-hashicorp-key-management-token="{vault_access_token}" +loose-hashicorp-key-management-check-kv-version="off" +#max timeout is 86400 seconds +loose-hashicorp-key-management-timeout=3000 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +#1 year in miliseconds +loose-hashicorp-key-management-cache-timeout=31556952000 +#1 year in miliseconds +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +#Example of innodb config +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = ON +innodb_encrypt_log = ON +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 \ No newline at end of file diff --git a/etc/example/policy.json b/etc/example/policy.json new file mode 100644 index 0000000..8e00e02 --- /dev/null +++ b/etc/example/policy.json @@ -0,0 +1,93 @@ +{ + "ruleUse": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleBlock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleUnblock": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "ruleModify": { + "tokens": [ + { + "name": "MAIN1", + "timelock": 0, + "timeout": 0, + "groups": [ + { + "name": "MAIN1", + "quorum": 1, + "approvals": [ + { + "type": "public_key", + "name": "replace_me_with_approval_name", + "value":"replace_me_with_approval_key" + } + ] + } + ] + } + ] + }, + "keyStatus": { + "blocked": false + } + } diff --git a/etc/release_notes/Release_Notes.md b/etc/release_notes/Release_Notes.md new file mode 100644 index 0000000..cfde364 --- /dev/null +++ b/etc/release_notes/Release_Notes.md @@ -0,0 +1,34 @@ +# Securosys Hashicorp Vault Secrets Engine 1.2.0 +Issued: Aug, 27, 2024 +## Feature +- Added support for TSB Api Keys + +# Securosys Hashicorp Vault Secrets Engine 1.1.0 +Issued: Dec, 6, 2023 +## Documentation Change +- Update Readme.md - added information about supporting and how to configure encryption on MariaDB +## Feature +- Added integration with MariaDB encryption +## Bugfix +- Fixed authentication with TSB using mTLS + +# Securosys Hashicorp Vault Secrets Engine 1.0.3 +Issued: Nov, 28, 2023 +## Documentation Change +- Update Readme.md - added CGO_ENABLED=0 in build command +## Bugfix +- Added CGO_ENABLED=0 to every build/ + +# Securosys Hashicorp Vault Secrets Engine 1.0.2 +Issued: Nov, 6, 2023 +## Documentation Change +- Update Readme.md +- Added License.txt + +# Securosys Hashicorp Vault Secrets Engine 1.0.1 +Issued: Sep, 18, 2023 +## Bugfix +- Removed sending empty password char array on not provided password. + +# Securosys Hashicorp Vault Secrets Engine 1.0.0 +Issued: May, 26, 2024 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2d78c0c --- /dev/null +++ b/go.mod @@ -0,0 +1,80 @@ +module secretengine + +go 1.21 + +toolchain go1.21.2 + +replace securosys.ch/helpers => ./helpers + +replace securosys.ch/backend => ./backend + +replace securosys.ch/client => ./client + +replace securosys.ch/test-helpers => ./testHelpers + +replace securosys.ch/tests => ./tests + +replace securosys.ch/integration/client => ./integrationTests/client + +replace securosys.ch/integration/tests => ./integrationTests/tests + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/sdk v0.9.1 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/frankban/quicktest v1.14.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afae25d --- /dev/null +++ b/go.sum @@ -0,0 +1,254 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work new file mode 100644 index 0000000..ad36518 --- /dev/null +++ b/go.work @@ -0,0 +1,8 @@ +go 1.21 + +use ( + ./ + ./backend + ./integrationTests/client + ./integrationTests/tests +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..976ca94 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,164 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/helpers/consts.go b/helpers/consts.go new file mode 100644 index 0000000..5c94d41 --- /dev/null +++ b/helpers/consts.go @@ -0,0 +1,59 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +// CONSTS +var UPDATE_POLICY_ON = []string{"Block", "UnBlock", "Modify"} + +var SUPPORTED_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS", "AES", "ChaCha20", "Camellia", "TDEA"} +var SYMMETRIC_KEY_TYPES = []string{"AES", "Camellia", "ChaCha20", "TDEA"} +var ASYMMETRIC_KEY_TYPES = []string{"EC", "ED", "RSA", "DSA", "BLS"} + +var RSA_CIPHER_LIST = []string{"RSA_PADDING_OAEP_WITH_SHA512", "RSA", "RSA_PADDING_OAEP_WITH_SHA224", "RSA_PADDING_OAEP_WITH_SHA256", "RSA_PADDING_OAEP_WITH_SHA1", "RSA_PADDING_OAEP", "RSA_PADDING_OAEP_WITH_SHA384", "RSA_NO_PADDING"} +var AES_CIPHER_LIST = []string{"AES_GCM", "AES_CTR", "AES_ECB", "AES_CBC_NO_PADDING", "AES"} +var CHACHA20_CIPHER_LIST = []string{"CHACHA20", "CHACHA20_AEAD"} +var CAMELIA_CIPHER_LIST = []string{"CAMELLIA", "CAMELLIA_CBC_NO_PADDING", "CAMELLIA_ECB"} +var TDEA_CIPHER_LIST = []string{"TDEA_CBC", "TDEA_ECB", "TDEA_CBC_NO_PADDING"} + +var AES_WRAP_METHODS_LIST = []string{"AES_WRAP", "AES_WRAP_DSA", "AES_WRAP_EC", "AES_WRAP_ED", "AES_WRAP_RSA", "AES_WRAP_BLS", "AES_WRAP_PAD", "AES_WRAP_PAD_DSA", "AES_WRAP_PAD_EC", "AES_WRAP_PAD_ED", "AES_WRAP_PAD_RSA", "AES_WRAP_PAD_BLS"} +var RSA_WRAP_METHODS_LIST = []string{"RSA_WRAP_PAD", "RSA_WRAP_OAEP"} + +var SUPPORTED_ENCRYPT_DECRYPT_KEYS = []string{"RSA", "AES", "CHACHA20", "CAMELLIA", "TDEA"} +var SUPPORTED_WRAP_KEYS = []string{"RSA", "AES"} +var SUPPORTED_SIGN_KEYS = []string{"EC", "ED", "RSA", "DSA", "BLS"} +var SUPPORTED_CERTIFICATE_SIGN_KEYS = []string{"RSA"} +var CERTIFICATE_RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA"} + +var EC_SIGNATURE_LIST = []string{"NONE_WITH_ECDSA", "SHA1_WITH_ECDSA", "SHA224_WITH_ECDSA", "SHA256_WITH_ECDSA", "SHA384_WITH_ECDSA", "SHA512_WITH_ECDSA", "SHA3224_WITH_ECDSA", "SHA3256_WITH_ECDSA", "SHA3384_WITH_ECDSA", "SHA3512_WITH_ECDSA", "KECCAK224_WITH_ECDSA", "KECCAK256_WITH_ECDSA", "KECCAK384_WITH_ECDSA", "KECCAK512_WITH_ECDSA"} +var ED_SIGNATURE_LIST = []string{"EDDSA"} +var RSA_SIGNATURE_LIST = []string{"SHA224_WITH_RSA_PSS", "SHA256_WITH_RSA_PSS", "SHA384_WITH_RSA_PSS", "SHA512_WITH_RSA_PSS", "NONE_WITH_RSA", "SHA224_WITH_RSA", "SHA256_WITH_RSA", "SHA384_WITH_RSA", "SHA512_WITH_RSA", "SHA1_WITH_RSA", "SHA1_WITH_RSA_PSS"} +var DSA_SIGNATURE_LIST = []string{"NONE_WITH_DSA", "SHA224_WITH_DSA", "SHA256_WITH_DSA", "SHA384_WITH_DSA", "SHA512_WITH_DSA", "SHA1_WITH_DSA"} +var BLS_SIGNATURE_LIST = []string{"BLS"} + +var SUPPORTED_PAYLOAD_TYPE = []string{"UNSPECIFIED", "ISO_20022", "PDF", "BTC", "ETH"} +var SUPPORTED_TAG_LENGTH = []string{"0", "64", "96", "104", "112", "120", "128"} + +var SUPPORTED_KEY_TYPE_NAME = []string{"aes256-gcm96", "rsa-2048", "rsa-3072", "rsa-4096", "ecdsa-p256", "ecdsa-p384", "ecdsa-p521"} + +var SUPPORTED_KEY_USAGE = []string{"DIGITAL_SIGNATURE", "CONTENT_COMMITMENT", "KEY_ENCIPHERMENT", "DATA_ENCIPHERMENT", "KEY_AGREEMENT", "KEY_CERT_SIGN", "CRL_SIGN", "ENCIPHER_ONLY", "DECIPHER_ONLY"} +var SUPPORTED_EXTENDED_KEY_USAGE = []string{"ANY_EXTENDED_KEY_USAGE", "SERVER_AUTH", "CLIENT_AUTH", "CODE_SIGNING", "EMAIL_PROTECTION", "TIME_STAMPING", "OCSP_SIGNING"} +var SUPPORTED_CERTIFICATE_ATTRIBUTES = []string{"commonName", "country", "stateOrProvinceName", "locality", "organizationName", "organizationUnitName", "email", "title", "surname", "givenName", "initials", "pseudonym", "generationQualifier"} + +//END CONSTS diff --git a/helpers/functions.go b/helpers/functions.go new file mode 100644 index 0000000..3dd9fb6 --- /dev/null +++ b/helpers/functions.go @@ -0,0 +1,286 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "bytes" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + b64 "encoding/base64" + "encoding/hex" + "encoding/json" + "encoding/pem" + "fmt" + "math/rand" + "reflect" + "strconv" + "strings" + "time" +) + +type approval struct { + TypeOfKey string `json:"type"` + Name *string `json:"name"` + Value string `json:"value"` +} +type group struct { + Name string `json:"name"` + Quorum int `json:"quorum"` + Approvals []approval `json:"approvals"` +} +type token struct { + Name string `json:"name"` + Timelock int `json:"timelock"` + Timeout int `json:"timeout"` + Groups []group `json:"groups"` +} +type rule struct { + Tokens []token `json:"tokens"` +} +type keyStatus struct { + Blocked bool `json:"blocked"` +} + +// Policy structure for rules use, block, unblock, modify +type Policy struct { + RuleUse rule `json:"ruleUse"` + RuleBlock rule `json:"ruleBlock"` + RuleUnBlock rule `json:"ruleUnblock"` + RuleModify rule `json:"ruleModify"` + KeyStatus *keyStatus `json:"keyStatus,omitempty"` +} + +// Function converts string into char array +func StringToCharArray(text string) []string { + var array []string = make([]string, 0) + for i := 0; i < len(text); i++ { + array = append(array, string(text[i])) + } + return array +} + +// Function that helps fill a policy structure +func PreparePolicy(policyString string, simplified bool) (*Policy, error) { + return PrepareFullPolicy(policyString, simplified, true) +} + +// Function that checking if key exists in map +func ContainsKey(m, k interface{}) bool { + v := reflect.ValueOf(m).MapIndex(reflect.ValueOf(k)) + return v != reflect.Value{} +} + +// This function preparing Policy structure for generating asynchronous keys +func PrepareFullPolicy(policyString string, simplified bool, addKeyStatus bool) (*Policy, error) { + var PolicyObj Policy + if simplified == true { + var simplePolicy map[string]string + err := json.Unmarshal([]byte(policyString), &simplePolicy) + if err != nil { + return nil, err + } + token := PreparePolicyTokens(simplePolicy) + PolicyObj.RuleUse.Tokens = append(PolicyObj.RuleUse.Tokens, token) + PolicyObj.RuleBlock.Tokens = append(PolicyObj.RuleBlock.Tokens, token) + PolicyObj.RuleUnBlock.Tokens = append(PolicyObj.RuleUnBlock.Tokens, token) + PolicyObj.RuleModify.Tokens = append(PolicyObj.RuleModify.Tokens, token) + if addKeyStatus == true { + PolicyObj.KeyStatus = new(keyStatus) + PolicyObj.KeyStatus.Blocked = false + } + } else { + err := json.Unmarshal([]byte(policyString), &PolicyObj) + if err != nil { + return nil, err + } + if addKeyStatus == false { + PolicyObj.KeyStatus = nil + } + + } + return &PolicyObj, nil +} + +// This function groups from simplePolicy parameter sended with keys + +func PreparePolicyTokens(policy map[string]string) token { + var group group + group.Name = "main" + group.Quorum = len(policy) + for name, element := range policy { + var approval approval + _, err := ReadCertificate(element) + if err != nil { + approval.TypeOfKey = "public_key" + approval.Name = &name + approval.Value = element + } else { + approval.TypeOfKey = "certificate" + approval.Value = element + + } + group.Approvals = append(group.Approvals, approval) + } + + var token token + token.Name = "main" + token.Timeout = 0 + token.Timelock = 0 + if len(policy) == 0 { + token.Groups = nil + } else { + token.Groups = append(token.Groups, group) + + } + + return token + +} + +// Function converts attributes map into a json +func PrepareAttributes(attributes map[string]bool) string { + json, _ := json.Marshal(attributes) + return string(json) + +} + +// Function checking if string exits in string array +func Contains(s []string, str string) bool { + for _, v := range s { + if strings.ToLower(v) == strings.ToLower(str) { + return true + } + } + + return false +} + +// Function returns new version of key +func GetNewVersion(version string) string { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + newVersion := "v" + strconv.Itoa(versionInt+1) + return newVersion +} +func GetVersionNumber(version string) int { + versionString := strings.Replace(version, "v", "", 1) + versionInt, _ := strconv.Atoi(versionString) + return versionInt +} +func GetVersionString(version string) string { + return strings.Replace(version, "v", "", 1) +} + +// Function preparing MetaData, which We are send with all asynchronous requests +func PrepareMetaData(requestType string, additionalMetaData map[string]string, customMetaData map[string]string) (string, string, error) { + now := time.Now().UTC() + var metaData map[string]string = make(map[string]string) + metaData["time"] = fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + metaData["app"] = "Hashicorp Vault - Securosys HSM Secrets Engine" + metaData["type"] = requestType + for key, value := range additionalMetaData { + metaData[key] = value + } + for key, value := range customMetaData { + metaData[key] = value + } + metaJsonStr, errMarshal := json.Marshal(metaData) + if errMarshal != nil { + return "", "", errMarshal + } + h := sha256.New() + h.Write(metaJsonStr) + bs := h.Sum(nil) + return b64.StdEncoding.EncodeToString(metaJsonStr), + b64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(bs))), nil +} + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + specialBytes = "!@#$%^&*()_+-=[]{}\\|;':\",.<>/?`~" + numBytes = "0123456789" + hexDecimalBytes = "0123456789ABCDEF" +) + +func MinifyJson(requestData string) string { + dst := &bytes.Buffer{} + if err := json.Compact(dst, []byte(requestData)); err != nil { + panic(err) + } + return dst.String() + +} + +func GeneratePassword(length int, useLetters bool, useSpecial bool, useNum bool, useHexadecimal bool) string { + rand.Seed(time.Now().UnixNano()) + b := make([]byte, length) + arrayForRandom := make([]byte, 0) + if useLetters { + arrayForRandom = append(arrayForRandom, letterBytes...) + } + if useSpecial { + arrayForRandom = append(arrayForRandom, specialBytes...) + } + if useNum { + arrayForRandom = append(arrayForRandom, numBytes...) + } + if useHexadecimal { + arrayForRandom = append(arrayForRandom, hexDecimalBytes...) + + } + + for i := range b { + b[i] = arrayForRandom[rand.Intn(len(arrayForRandom))] + } + return string(b) +} +func ReadCertificate(possibleCertificate string) (*x509.Certificate, error) { + block, _ := pem.Decode([]byte(possibleCertificate)) + if block == nil { + return nil, fmt.Errorf("Cannot read certificate") + } + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + return cert, nil +} +func BytesToPublicKey(pub []byte) *rsa.PublicKey { + block, _ := pem.Decode(pub) + enc := x509.IsEncryptedPEMBlock(block) + b := block.Bytes + var err error + if enc { + b, err = x509.DecryptPEMBlock(block, nil) + if err != nil { + return nil + } + } + ifc, err := x509.ParsePKIXPublicKey(b) + if err != nil { + return nil + } + key, ok := ifc.(*rsa.PublicKey) + if !ok { + return nil + } + return key +} diff --git a/helpers/go.mod b/helpers/go.mod new file mode 100644 index 0000000..6850ff3 --- /dev/null +++ b/helpers/go.mod @@ -0,0 +1,57 @@ +module securosys.ch/helpers + +replace securosys.ch/backend => ./../backend + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/go.sum b/helpers/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/helpers/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/mariadb_structs.go b/helpers/mariadb_structs.go new file mode 100644 index 0000000..7c23c7a --- /dev/null +++ b/helpers/mariadb_structs.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "time" + + "github.com/hashicorp/vault/sdk/logical" +) + +// INTEGRATION MARIADB STRUCTS +type Entity struct { + Id string `json:"id"` + Name string `json:"name"` + Aliases []*logical.Alias `json:"aliases"` + Date time.Time `json:"date"` +} +type MariaDBSecretEntry struct { + KeyName string `json:"keyName"` + Versions map[string]MariaDBSecretVersion `json:"secretVersions"` + CurrentVersion string `json:"defaultVersion"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +// Struct of keys stored inside the Vault +type MariaDBSecretVersion struct { + KeyVersion string `json:"keyVersion"` + EncryptedSecret string `json:"encryptedSecret"` + MessageAuthenticationCode *string `json:"messageAuthenticationCode"` + InitializationVector *string `json:"initializationVector"` + Version string `json:"version"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (s *MariaDBSecretEntry) InitSecret(keyName string, keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, creator Entity) { + s.CurrentVersion = "v1" + s.KeyName = keyName + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = "v1" + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = creator + secretVersion.Updated = creator + s.Created = creator + s.Updated = creator + s.Versions = make(map[string]MariaDBSecretVersion) + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) RotateSecret(keyVersion string, messageAuthenticationCode *string, initializationVector *string, encryptedSecret string, updater Entity) { + newSecretVersion := GetNewVersion(s.CurrentVersion) + s.CurrentVersion = newSecretVersion + secretVersion := &MariaDBSecretVersion{} + secretVersion.Version = newSecretVersion + secretVersion.KeyVersion = keyVersion + secretVersion.EncryptedSecret = encryptedSecret + secretVersion.MessageAuthenticationCode = messageAuthenticationCode + secretVersion.InitializationVector = initializationVector + secretVersion.Created = updater + secretVersion.Updated = updater + s.Updated = updater + s.Versions[s.CurrentVersion] = *secretVersion + +} +func (s *MariaDBSecretEntry) GetActiveVersion() MariaDBSecretVersion { + return s.Versions[s.CurrentVersion] +} +func (s *MariaDBSecretEntry) GetVersion(keyVersion string) MariaDBSecretVersion { + return s.Versions[keyVersion] +} + +// END INTEGRATION MARIADB STRUCTS diff --git a/helpers/structs.go b/helpers/structs.go new file mode 100644 index 0000000..4b1b6fb --- /dev/null +++ b/helpers/structs.go @@ -0,0 +1,417 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej, Mikolaj Szargut + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package helpers + +import ( + "crypto/rsa" + "encoding/json" +) + +// STRUCTS + +// Structure for all asychnronous operations +type RequestResponse struct { + Id string `json:"id"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy []string `json:"approvedBy"` + NotYetApprovedBy []string `json:"notYetApprovedBy"` + RejectedBy []string `json:"rejectedBy"` + Result string `json:"result"` +} + +// Structure for get key attributes response +type KeyAttributes struct { + Label string + Attributes map[string]bool + KeySize float64 + Policy Policy + PublicKey string + Algorithm string + AlgorithmOid string + CurveOid string + Version string + Active bool + Xml string + XmlSignature string + AttestationKeyName string +} + +// SecurosysConfig includes the minimum configuration +// required to instantiate a new HashiCups client. +type SecurosysConfig struct { + Auth string `json:"auth"` + BearerToken string `json:"bearertoken"` + Username string `json:"username"` + Password string `json:"password"` + BasicToken string `json:"basictoken"` + CertPath string `json:"certpath"` + KeyPath string `json:"keypath"` + RestApi string `json:"restapi"` + AppName string `json:"appName"` + ApplicationKeyPair string `json:"applicationKeyPair"` + ApiKeys string `json:"apiKeys"` +} + +// Structure for certificate operations +type RequestResponseCertificate struct { + Label string `json:"label"` + Certificate string `json:"certificate"` +} + +// Structure for certificate operations +type RequestResponseImportCertificate struct { + Label string `json:"label"` + Certificate string `json:"certificate"` +} + +type GenerateCertificateRequest struct { + // The same key id as passed in the request. + KeyID string `json:"keyId"` + PluginConfig map[string]string `json:"pluginConfig,omitempty"` + Certificate Certificate `json:"certificate"` +} + +type CertificateAttributes struct { + CommonName string `json:"commonName"` + Country *string `json:"country"` + StateOrProvinceName *string `json:"stateOrProvinceName"` + Locality *string `json:"locality"` + OrganizationName *string `json:"organizationName"` + OrganizationUnitName *string `json:"organizationUnitName"` + Email *string `json:"email"` + Title *string `json:"title"` + Surname *string `json:"surname"` + GivenName *string `json:"givenName"` + Initials *string `json:"initials"` + Pseudonym *string `json:"pseudonym"` + GenerationQualifier *string `json:"generationQualifier"` +} + +func (ca *CertificateAttributes) ToString() string { + respData := map[string]interface{}{ + "commonName": ca.CommonName, + "country": ca.Country, + "organizationName": ca.OrganizationName, + } + jsonStr, _ := json.Marshal(respData) + return string(jsonStr[:]) +} + +type Certificate struct { + Validity int `json:"validity"` + Attributes CertificateAttributes `json:"attributes"` +} + +type ImportCertificateRequest struct { + // The same key id as passed in the request. + KeyID string `json:"keyId"` + PluginConfig map[string]string `json:"pluginConfig,omitempty"` +} + +type GenerateCertificateResponse struct { + // The same key id as passed in the request. + KeyID string `json:"label"` + Certificate string `json:"certificate"` + KeyVersion string `json:"keyVersion"` +} + +type GenerateCertificateRequestResponse struct { + // The same key id as passed in the request. + KeyID string `json:"label"` + CertificateRequest string `json:"certificateSigningRequest"` + KeyVersion string `json:"keyVersion"` +} + +type GenerateSelfSignedCertificateResponse struct { + // The same key id as passed in the request. + KeyID string `json:"label"` + KeyVersion string `json:"keyVersion"` + + CertificateRequest string `json:"certificate"` +} +type DecryptResponse struct { + Payload string `json:"payload"` +} +type EncryptResponse struct { + EncryptedPayload string `json:"encryptedPayload"` + EncryptedPayloadWithoutMessageAuthenticationCode string `json:"encryptedPayloadWithoutMessageAuthenticationCode"` + InitializationVector *string `json:"initializationVector"` + MessageAuthenticationCode *string `json:"messageAuthenticationCode"` + KeyVersion string `json:"keyVersion"` +} +type SignatureResponse struct { + Signature string `json:"signature"` + KeyVersion string `json:"keyVersion"` +} +type WrapResponse struct { + WrappedKey string `json:"wrappedKey"` + KeyVersion string `json:"keyVersion"` +} +type KeyEntry struct { + BaseLabel string `json:"baseLabel"` + Algorithm string `json:"algorithm"` + AlgorithmOid string `json:"algorithmOid"` + KeySize float64 `json:"keySize"` + KeyTypeName string `json:"keyTypeName"` + Attributes map[string]bool `json:"attributes"` + CurveOid string `json:"curveOid"` + Versions map[string]KeyVersion `json:"keyVersions"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` + CurrentVersion string `json:"defaultVersion"` +} +type KeyVersion struct { + KeyLabel string `json:"keyLabel"` + Version string `json:"version"` + Policy Policy `json:"policy"` + PublicKey string `json:"publicKey"` + PrivateKey string `json:"privateKey"` + SecretKey string `json:"secretKey"` + Certificate string `json:"certificate"` + Xml string `json:"xml"` + XmlSignature string `json:"xmlSignature"` + AttestationKeyName string `json:"attestationKeyName"` + Password string `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *KeyVersion) ToResponseData(key KeyEntry) map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.KeyLabel, + "policy": r.Policy, + "algorithm": key.Algorithm, + "algorithmOid": key.AlgorithmOid, + "keySize": key.KeySize, + "attributes": key.Attributes, + "publicKey": r.PublicKey, + "privateKey": r.PrivateKey, + "version": r.Version, + "secretKey": r.SecretKey, + "attestationKeyName": r.AttestationKeyName, + "certificate": r.Certificate, + "curveOid": key.CurveOid, + "created": r.Created, + "updated": r.Updated, + } + if key.KeySize == 0 { + delete(respData, "keySize") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if r.PrivateKey == "" { + delete(respData, "privateKey") + } + if r.PublicKey == "" { + delete(respData, "publicKey") + } + if r.SecretKey == "" { + delete(respData, "secretKey") + } + if key.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, key.Algorithm) { + delete(respData, "policy") + } + return respData +} + +// This function prints names instead of public_key using policy +func (r *KeyEntry) GetPolicyWithName(policy []string, ruleType string) map[string]string { + var list map[string]string = make(map[string]string) + var policyTokens []token + if ruleType == "Block" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleBlock.Tokens + } else if ruleType == "UnBlock" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUnBlock.Tokens + } else if ruleType == "Modify" { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleModify.Tokens + } else { + policyTokens = r.Versions[r.CurrentVersion].Policy.RuleUse.Tokens + } + + for _, token := range policyTokens { + for _, group := range token.Groups { + for _, approval := range group.Approvals { + if Contains(policy, approval.Value) && approval.TypeOfKey == "public_key" { + list[*approval.Name] = approval.Value + } else { + cert, err := ReadCertificate(approval.Value) + if err == nil { + for _, publicKey := range policy { + key := BytesToPublicKey([]byte("-----BEGIN RSA PUBLIC KEY-----\n" + publicKey + "\n-----END RSA PUBLIC KEY-----")) + if cert.PublicKey.(*rsa.PublicKey).N.Cmp(key.N) == 0 && key.E == cert.PublicKey.(*rsa.PublicKey).E { + list[*approval.Name] = publicKey + break + } + } + + } + } + + } + } + } + + return list +} + +// This function prints key information +func (r *KeyEntry) ToResponseData() map[string]interface{} { + + respData := map[string]interface{}{ + "baseLabel": r.BaseLabel, + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "policy": r.Versions[r.CurrentVersion].Policy, + "algorithm": r.Algorithm, + "algorithmOid": r.AlgorithmOid, + "keySize": r.KeySize, + "attributes": r.Attributes, + "version": r.CurrentVersion, + "publicKey": r.Versions[r.CurrentVersion].PublicKey, + "privateKey": r.Versions[r.CurrentVersion].PrivateKey, + "secretKey": r.Versions[r.CurrentVersion].SecretKey, + "attestationKeyName": r.Versions[r.CurrentVersion].AttestationKeyName, + "certificate": r.Versions[r.CurrentVersion].Certificate, + "curveOid": r.CurveOid, + "keyTypeName": r.KeyTypeName, + "created": r.Created, + "updated": r.Updated, + } + if r.KeySize == 0 { + delete(respData, "keySize") + } + if r.KeyTypeName == "" { + delete(respData, "keyTypeName") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.Versions[r.CurrentVersion].PrivateKey == "" { + delete(respData, "privateKey") + } + if r.Versions[r.CurrentVersion].PublicKey == "" { + delete(respData, "publicKey") + } + if r.Versions[r.CurrentVersion].SecretKey == "" { + delete(respData, "secretKey") + } + if r.CurveOid == "" { + delete(respData, "curveOid") + } + if r.Versions[r.CurrentVersion].Certificate == "" { + delete(respData, "certificate") + } + if Contains(SYMMETRIC_KEY_TYPES, r.Algorithm) { + delete(respData, "policy") + + } + return respData +} + +// This method updates key information based on changes in HSM +func (r *KeyEntry) UpdateKeyFromHSMWithRequest(key KeyAttributes, request RequestEntry) { + if entry, ok := request.Key.Versions[request.KeyVersion]; ok { + entry.Policy = key.Policy + entry.Updated = request.Created + + } + + r.Updated = request.Created + +} +func (r *KeyEntry) UpdateKeyFromHSM(key KeyAttributes) { + if entry, ok := r.Versions[r.CurrentVersion]; ok { + entry.Policy = key.Policy + } +} +func (r *KeyEntry) GetActiveVersionKeyLabel() string { + return r.Versions[r.CurrentVersion].KeyLabel +} +func (r *KeyEntry) GetActiveVersion() KeyVersion { + return r.Versions[r.CurrentVersion] +} +func (r *KeyEntry) GetVersion(keyVersion string) KeyVersion { + return r.Versions[keyVersion] +} + +// This method prints XML and Signature for a key +func (r *KeyEntry) ToResponseDataXML() map[string]interface{} { + respData := map[string]interface{}{ + "keyLabel": r.Versions[r.CurrentVersion].KeyLabel, + "xml": r.Versions[r.CurrentVersion].Xml, + "xmlSignature": r.Versions[r.CurrentVersion].XmlSignature, + } + return respData +} + +type RequestEntry struct { + Id string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + ExecutionTime string `json:"executionTime"` + ApprovedBy map[string]string `json:"approvedBy"` + NotYetApprovedBy map[string]string `json:"notYetApprovedBy"` + RejectedBy map[string]string `json:"rejectedBy"` + KeyPassword string `json:"keyPassword"` + Result string `json:"result"` + Request map[string]string `json:"request"` + Key KeyEntry `json:"key"` + KeyVersion string `json:"keyVersion"` + KeyUpdated bool `json:"-"` + Created Entity `json:"created"` + Updated Entity `json:"updated"` +} + +func (r *RequestEntry) UpdateStatus(request RequestResponse) { + r.Result = request.Result + r.Status = request.Status + r.ExecutionTime = request.ExecutionTime + r.ApprovedBy = r.Key.GetPolicyWithName(request.ApprovedBy, r.Type) + r.NotYetApprovedBy = r.Key.GetPolicyWithName(request.NotYetApprovedBy, r.Type) + r.RejectedBy = r.Key.GetPolicyWithName(request.RejectedBy, r.Type) + +} + +// toResponseData returns response data for a role +func (r *RequestEntry) ToResponseData() map[string]interface{} { + respData := map[string]interface{}{ + "id": r.Id, + "type": r.Type, + "request": r.Request, + "status": r.Status, + "executionTime": r.ExecutionTime, + "approvedBy": r.ApprovedBy, + "notYetApprovedBy": r.NotYetApprovedBy, + "rejectedBy": r.RejectedBy, + "result": r.Result, + "created": r.Created, + "updated": r.Updated, + } + return respData +} + +//END STRUCTS diff --git a/integrationTests/client/client.go b/integrationTests/client/client.go new file mode 100644 index 0000000..a5225df --- /dev/null +++ b/integrationTests/client/client.go @@ -0,0 +1,30 @@ +package integrationClient + +import ( + "fmt" + "log" + "os" + "time" + + "github.com/hashicorp/vault-client-go" +) + +func InitVaultClient() *vault.Client { + + // prepare a client with the given base address + client, err := vault.New( + vault.WithAddress(VaultConfig.Url+":"+fmt.Sprint(VaultConfig.Port)), + vault.WithRequestTimeout(300*time.Second), + ) + if err != nil { + log.Fatal(err) + os.Exit(1) + } + + // authenticate with a root token (insecure) + if err := client.SetToken(VaultConfig.RootToken); err != nil { + log.Fatal(err) + os.Exit(1) + } + return client +} diff --git a/integrationTests/client/client_config.go b/integrationTests/client/client_config.go new file mode 100644 index 0000000..148f2a9 --- /dev/null +++ b/integrationTests/client/client_config.go @@ -0,0 +1,15 @@ +package integrationClient + +type VaultClientConfig struct { + Port int + Url string + RootToken string + SecretsEnginePath string +} + +var VaultConfig VaultClientConfig=VaultClientConfig{ + Port: 8251, + Url: "http://127.0.0.1", + RootToken: "root", + SecretsEnginePath: "securosys-hsm", +} \ No newline at end of file diff --git a/integrationTests/client/go.mod b/integrationTests/client/go.mod new file mode 100644 index 0000000..02d12cd --- /dev/null +++ b/integrationTests/client/go.mod @@ -0,0 +1,24 @@ +module securosys.ch/integration/client + +go 1.21 + +toolchain go1.21.2 + +require github.com/hashicorp/vault-client-go v0.4.2 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stretchr/testify v1.8.2 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect +) diff --git a/integrationTests/client/go.sum b/integrationTests/client/go.sum new file mode 100644 index 0000000..3a52bd0 --- /dev/null +++ b/integrationTests/client/go.sum @@ -0,0 +1,58 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/vault-client-go v0.4.2 h1:XeUXb5jnDuCUhC8HRpkdGPLh1XtzXmiOnF0mXEbARxI= +github.com/hashicorp/vault-client-go v0.4.2/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integrationTests/docker/docker-compose.yml b/integrationTests/docker/docker-compose.yml new file mode 100644 index 0000000..d1dc502 --- /dev/null +++ b/integrationTests/docker/docker-compose.yml @@ -0,0 +1,40 @@ +version: "3.0" +name: hashicorp-vault-test-containers +services: + hashicorp-vault-test: + image: hashicorp/vault:latest + container_name: "hashicorp-vault-test" + environment: + VAULT_DEV_ROOT_TOKEN_ID: root + VAULT_ADDR: 'https://0.0.0.0:8251' + VAULT_LOCAL_CONFIG: '{"listener": [{"tcp":{"address": "0.0.0.0:8251","tls_disable":"1"}}], "default_lease_ttl": "168h", "max_lease_ttl": "720h"}, "ui": true}' + volumes: + - ./plugins/:/vault/plugins + - ../../testHelpers/:/testHelpers + cap_add: + - IPC_LOCK + healthcheck: + retries: 5 + ports: + - "8251:8251" + privileged: true + command: server -dev -dev-root-token-id=root -dev-plugin-dir=/vault/plugins + # networks: + # - web + # mariadb-test-integration: + # build: + # dockerfile: ./docker-files/MariaDB_Dockerfile + # container_name: "mariadb-test-integration" + # restart: always + # environment: + # MARIADB_ROOT_PASSWORD: example + # volumes: + # - ./mysql-config:/etc/mysql/conf.d + # - ./db:/var/lib/mysql + # networks: + # - web + +# networks: +# web: +# external: true + \ No newline at end of file diff --git a/integrationTests/docker/docker-files/MariaDB_Dockerfile b/integrationTests/docker/docker-files/MariaDB_Dockerfile new file mode 100644 index 0000000..7e5d37a --- /dev/null +++ b/integrationTests/docker/docker-files/MariaDB_Dockerfile @@ -0,0 +1,2 @@ +FROM mariadb:latest +RUN apt-get update && apt-get install -y mariadb-plugin-hashicorp-key-management diff --git a/integrationTests/docker/mysql-config/hashicorp.cnf b/integrationTests/docker/mysql-config/hashicorp.cnf new file mode 100644 index 0000000..1210099 --- /dev/null +++ b/integrationTests/docker/mysql-config/hashicorp.cnf @@ -0,0 +1,18 @@ +[mariadb] +plugin-load-add=hashicorp_key_management.so +loose-hashicorp-key-management +loose-hashicorp-key-management-vault-url="http://172.17.0.3:8251/v1/securosys-hsm/integrations/mariadb/test_async/?cipher_algorithm=RSA&key_name=rsa_with_policy&version=" +loose-hashicorp-key-management-token="root" +loose-hashicorp-key-management-check-kv-version="off" +loose-hashicorp-key-management-timeout=10 +loose-hashicorp-key-management-retries=0 +loose-hashicorp-key-management-use-cache-on-timeout="on" +loose-hashicorp-key-management-caching-enabled="on" +loose-hashicorp-key-management-cache-timeout=31556952000 +loose-hashicorp-key-management-cache-version-timeout=31556952000 + +innodb_encrypt_tables = ON +innodb_encrypt_temporary_tables = OFF +innodb_encrypt_log = OFF +innodb_encryption_threads = 4 +innodb_encryption_rotate_key_age = 1 diff --git a/integrationTests/tests/a_enable_plugin_test.go b/integrationTests/tests/a_enable_plugin_test.go new file mode 100644 index 0000000..d16575a --- /dev/null +++ b/integrationTests/tests/a_enable_plugin_test.go @@ -0,0 +1,48 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "testing" + + "github.com/hashicorp/vault-client-go/schema" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestEnablePlugin(t *testing.T) { + + t.Run("A.1 Test Enable Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.System.MountsEnableSecretsEngine(ctx,integrationClient.VaultConfig.SecretsEnginePath,schema.MountsEnableSecretsEngineRequest{ + Type: "securosys-hsm", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/b_config_plugin_test.go b/integrationTests/tests/b_config_plugin_test.go new file mode 100644 index 0000000..d777766 --- /dev/null +++ b/integrationTests/tests/b_config_plugin_test.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfigPlugin(t *testing.T) { + + t.Run("B.1 Test Config Plugin", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/config",testHelpers.ConfigParams) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data["result"]==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s","null").Error()) + } + + if(!strings.Contains(resp.Data["result"].(string),"Connection successful:")){ + assert.FailNow(t, fmt.Errorf("Expected: Connection successful got %s",resp.Data["result"]).Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_aes_key_test.go b/integrationTests/tests/c_create_aes_key_test.go new file mode 100644 index 0000000..ccffd1b --- /dev/null +++ b/integrationTests/tests/c_create_aes_key_test.go @@ -0,0 +1,234 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateAESKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_aes"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_aes got %s","null").Error()) + } + }) + t.Run("C.3 Read AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyAES_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["secretKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Key Secret got %s","null").Error()) + } + }) + t.Run("C.8 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_key_by_keyname_test.go b/integrationTests/tests/c_create_key_by_keyname_test.go new file mode 100644 index 0000000..285e47c --- /dev/null +++ b/integrationTests/tests/c_create_key_by_keyname_test.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateKeyByKeyNamePlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with label integrationTestKeyRSAName using name rsa-2048", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/type/rsa-2048/integration_test_key_rsa_name",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSAName", + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSAName"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSAName",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSAName_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test Remove Key RSA Key with name integrationTestKeyRSAName", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa_name",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_rsa_key_test.go b/integrationTests/tests/c_create_rsa_key_test.go new file mode 100644 index 0000000..90c1a10 --- /dev/null +++ b/integrationTests/tests/c_create_rsa_key_test.go @@ -0,0 +1,250 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeyRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeyRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Export RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/export",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + if(resp.Data["publicKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Public Key got %s","null").Error()) + } + if(resp.Data["privateKey"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Private Key got %s","null").Error()) + } + }) + t.Run("C.8 Update password RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa/update-password",map[string]interface{}{ + "password":"", + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Test Remove Key RSA Key with name integrationTestKeyRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/c_create_smart_rsa_key_test.go b/integrationTests/tests/c_create_smart_rsa_key_test.go new file mode 100644 index 0000000..dfdd792 --- /dev/null +++ b/integrationTests/tests/c_create_smart_rsa_key_test.go @@ -0,0 +1,255 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestCreateSmartRSAKeyPlugin(t *testing.T) { + + t.Run("C.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.2 Test List Keys", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of keys got %s","null").Error()) + } + if(keyInfo["integration_test_smart_key_rsa"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: integration_test_smart_key_rsa got %s","null").Error()) + } + }) + t.Run("C.3 Read Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.4 Rotate Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/rotate",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.5 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,err:=client.List(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa") + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(resp.Data["key_info"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + + } + keyInfo:=resp.Data["key_info"].(map[string]interface{}); + if(keyInfo==nil){ + assert.FailNow(t, fmt.Errorf("Expected: List of key versions got %s","null").Error()) + } + if(keyInfo["v1"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v1 got %s","null").Error()) + } + if(keyInfo["v2"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: v2 got %s","null").Error()) + } + }) + t.Run("C.6 Test List Versions of Key integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + resp,_:=client.Read(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/v2") + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["version"].(string)!="v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v2",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v2"){ + assert.FailNow(t, fmt.Errorf("Expected: Key Label %s got %s","integrationTestKeySmartRSA_v2",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("C.7 Block Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/block",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.8 UnBlock Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/unblock",map[string]interface{}{}) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.9 Update password Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _ ,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/update-password",map[string]interface{}{ + "password":nil, + "newPassword":"test", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("C.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/d_operations_on_key_test.go b/integrationTests/tests/d_operations_on_key_test.go new file mode 100644 index 0000000..8dc951b --- /dev/null +++ b/integrationTests/tests/d_operations_on_key_test.go @@ -0,0 +1,329 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package integrationTests + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "testing" + + "github.com/hashicorp/vault-client-go" + "github.com/stretchr/testify/assert" + integrationClient "securosys.ch/integration/client" +) + +func TestOperationsOnKeyPlugin(t *testing.T) { + + t.Run("D.1 Test Create Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/rsa/integration_test_smart_key_rsa",map[string]interface{}{ + "keyLabel":"integrationTestKeySmartRSA", + "keySize":2048, + "attributes": `{ + "decrypt": true, + "sign": true, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": false, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + "simplePolicy":"{}", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="RSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","RSA",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeySmartRSA"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeySmartRSA",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("2048")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","2048",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeySmartRSA_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeySmartRSA_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.2 Test Create Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/aes/integration_test_key_aes",map[string]interface{}{ + "keyLabel":"integrationTestKeyAES", + "keySize":256, + "attributes": `{ + "decrypt": true, + "sign": false, + "unwrap": true, + "derive": true, + "sensitive": false, + "alwaysSensitive": false, + "extractable": true, + "neverExtractable": true, + "modifiable": true, + "copyable": false, + "destroyable": true + }`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Key response got %s","null").Error()) + } + if(resp.Data["algorithm"].(string)!="AES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key type %s got %s","AES",resp.Data["algorithm"]).Error()) + } + if(resp.Data["baseLabel"].(string)!="integrationTestKeyAES"){ + assert.FailNow(t, fmt.Errorf("Expected: Key name %s got %s","integrationTestKeyAES",resp.Data["baseLabel"]).Error()) + } + if(resp.Data["version"].(string)!="v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key version %s got %s","v1",resp.Data["version"]).Error()) + } + if(resp.Data["keySize"].(json.Number)!=json.Number("256")){ + assert.FailNow(t, fmt.Errorf("Expected: Key size %s got %s","256",resp.Data["keySize"]).Error()) + } + if(resp.Data["keyLabel"].(string)!="integrationTestKeyAES_v1"){ + assert.FailNow(t, fmt.Errorf("Expected: Key label %s got %s","integrationTestKeyAES_v1",resp.Data["keyLabel"]).Error()) + } + }) + t.Run("D.3 Test Encrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.4 Test Encrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + }) + t.Run("D.5 Test Decrypt using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_smart_key_rsa",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.6 Test Decrypt using integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/encrypt/integration_test_key_aes",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload got %s","null").Error()) + } + if(resp.Data["encryptedPayload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Encrypted payload %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/decrypt/integration_test_key_aes",map[string]interface{}{ + "encryptedPayload":resp.Data["encryptedPayload"].(string), + "keyVersion":"v1", + "initializationVector":resp.Data["initializationVector"], + "cipherAlgorithm":"AES", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Payload got %s","null").Error()) + } + if(resp.Data["payload"]!="cGF5bG9hZAo="){ + assert.FailNow(t, fmt.Errorf("Expected: Payload %s got %s","cGF5bG9hZAo=",resp.Data["payload"]).Error()) + } + + }) + t.Run("D.7 Test Sign using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + }) + t.Run("D.8 Test Verify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + resp,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/sign/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "signatureAlgorithm":"SHA256_WITH_RSA", + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: Signature got %s","null").Error()) + } + if(resp.Data["signature"]==nil){ + assert.FailNow(t, fmt.Errorf("Expected: Signature %s","null").Error()) + } + resp,err=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/operation/verify/integration_test_smart_key_rsa",map[string]interface{}{ + "payload":"cGF5bG9hZAo=", + "keyVersion":"v1", + "signatureAlgorithm":"SHA256_WITH_RSA", + "signature":resp.Data["signature"].(string), + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp==nil || resp.Data==nil{ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid got %s","null").Error()) + } + if(resp.Data["signatureValid"]==false){ + assert.FailNow(t, fmt.Errorf("Expected: SignatureValid %s got %s","true",resp.Data["signatureValid"]).Error()) + } + }) + t.Run("D.9 Test Modify using integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + + _,err:=client.Write(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa/modify",map[string]interface{}{ + "simplePolicy":`{"test":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnydX62tLYNF+Op1SRnX6avkkyQWlpYPagH85zxaGnMlZoMioqgjSOCuRvjaP7Y5noPMYayp3gJ2PwLXvw9+JlnL+iwklOcpONSa6gDoCDsk26DOoY0ELEPaGdW61mc2bj2hOQE0GEpPsRywJoRLS3B2e8bqRfAniAfGsUq3MK09iL5YOCuUCHCUiR9iZMSt0+Ek/kE4TrazbOCev1g6Ux2vOyTuQ6mF3wVuqwd8RhfvlNNKXbD2GD/jR3BwuhaodwzRPmDyDQPmEMwornxrMLavTcC+Igb4k5qol0Di6Oq8axpBvrH7KlxHT11Wd+ALKCsqoPSGxcIbd6TdN+ag9AQIDAQAB"}`, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.10 Test Remove Key Smart RSA Key with name integrationTestKeySmartRSA", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_smart_key_rsa",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) + t.Run("D.11 Test Remove Key AES Key with name integrationTestKeyAES", func(t *testing.T) { + ctx := context.Background() + + client:=integrationClient.InitVaultClient() + _,err:=client.Delete(ctx,integrationClient.VaultConfig.SecretsEnginePath+"/keys/integration_test_key_aes",vault.WithQueryParameters(url.Values{ + "removeFromHSM": {"true"}, + })) + if err != nil { + assert.FailNow(t, err.Error()) + } + }) +} + + + diff --git a/integrationTests/tests/go.mod b/integrationTests/tests/go.mod new file mode 100644 index 0000000..02bc999 --- /dev/null +++ b/integrationTests/tests/go.mod @@ -0,0 +1,6 @@ +module securosys.ch/integration/tests + +replace securosys.ch/integration/client => ./../client +replace securosys.ch/test-helpers => ./../../testHelpers + +go 1.19 diff --git a/integrationTests/tests/go.sum b/integrationTests/tests/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..12261b8 --- /dev/null +++ b/project.properties @@ -0,0 +1 @@ +VERSION=1.2.0 \ No newline at end of file diff --git a/testHelpers/go.mod b/testHelpers/go.mod new file mode 100644 index 0000000..eeb318c --- /dev/null +++ b/testHelpers/go.mod @@ -0,0 +1,61 @@ +module securosys.ch/test-helper + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/backend v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/helpers v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/testHelpers/go.sum b/testHelpers/go.sum new file mode 100644 index 0000000..61ab574 --- /dev/null +++ b/testHelpers/go.sum @@ -0,0 +1,225 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testHelpers/test_client_tsb.go b/testHelpers/test_client_tsb.go new file mode 100644 index 0000000..f93eb37 --- /dev/null +++ b/testHelpers/test_client_tsb.go @@ -0,0 +1,167 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/http" + "time" +) + +// HostURL - Default Securosys TSB URL +const HostURL string = "" + +// TSBClient struct +type TestTSBClient struct { + HostURL string + HTTPClient *http.Client +} + +// Function inicialize new client for accessing TSB +func NewTestTSBClient() (*TestTSBClient, error) { + c := TestTSBClient{ + HTTPClient: &http.Client{Timeout: 9999999 * time.Second}, + // Default Hashicups URL + HostURL: ConfigParams["restapi"].(string), + } + + return &c, nil +} + +// Function thats send request modify key to TSB + +func (c *TestTSBClient) GetApprovalTasks(taskType string) (string, string, error) { + path := "" + switch taskType { + case "Block": + path = "/v1/filteredBlockKeyApprovalTask" + case "Decrypt": + path = "/v1/filteredDecryptApprovalTask" + case "Modify": + path = "/v1/filteredModifyKeyApprovalTask" + case "Sign": + path = "/v1/filteredSignApprovalTask" + case "UnBlock": + path = "/v1/filteredUnblockKeyApprovalTask" + case "UnWrap": + path = "/v1/filteredUnwrapKeyApprovalTask" + } + now := time.Now() + + // Convert the time to UTC + utc := now.UTC() + + // Format the time using the same layout as JavaScript's toISOString() + iso8601 := fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + utc.Year(), utc.Month(), utc.Day(), + utc.Hour(), utc.Minute(), utc.Second(), utc.Nanosecond()/1e6) + + var jsonStr = []byte(`{ + "timestamp":"` + iso8601 + `", + "timestampSignature":"` + Sign([]byte(iso8601)) + `", + "approverPublicKey":"` + GetPublicKey() + `", + "detailLevel": "level5", + "timestampDigestAlgorithm":"SHA-256", + "paging": { + "pageNumber": 0, + "pageSize": 25, + "sortOrder": "CREATION_DATE_ASC" + }}`) + req, err := http.NewRequest("POST", c.HostURL+path, bytes.NewBuffer(jsonStr)) + if err != nil { + return "", "", err + } + body, _, err := c.doRequestApproval(req) + var result map[string]interface{} + _ = json.Unmarshal(body, &result) + if err != nil { + return "", "", err + } + tasks := result["tasks"].([]interface{}) + task := tasks[0].(map[string]interface{}) + id := task["id"].(string) + approvalToBeSigned := task["approvalToBeSigned"].(string) + return id, approvalToBeSigned, nil +} +func (c *TestTSBClient) MakeApproval(id string, approvalToBeSigned string) (bool, error) { + // Format the time using the same layout as JavaScript's toISOString() + data, _ := base64.StdEncoding.DecodeString(approvalToBeSigned) + var jsonStr = []byte(`{ + "signature":"` + Sign(data) + `", + "approvalDigestAlgorithm":"SHA-256", + "approverPublicKey":"` + GetPublicKey() + `", + "approvalToBeSigned":"` + approvalToBeSigned + `", + "id":"` + id + `"}`) + req, err := http.NewRequest("POST", c.HostURL+"/v1/approval", bytes.NewBuffer(jsonStr)) + if err != nil { + return false, err + } + _, code, err := c.doRequestApproval(req) + if err != nil { + return false, err + } + if code == 200 { + return true, nil + } else { + return false, fmt.Errorf("Wrong result code. Expected 200 got %d", code) + } +} + +// Function that making all requests. Using config for Authorization to TSB + +type ApiKeyTypes struct { + KeyManagementToken []string `json:"KeyManagementToken,omitempty"` + KeyOperationToken []string `json:"KeyOperationToken,omitempty"` + ApproverToken []string `json:"ApproverToken,omitempty"` + ServiceToken []string `json:"ServiceToken,omitempty"` + ApproverKeyManagementToken []string `json:"ApproverKeyManagementToken,omitempty"` +} + +func (c *TestTSBClient) doRequestApproval(req *http.Request) ([]byte, int, error) { + // req.Header.Set("Authorization", c.Token) + apiKeys := ConfigParams["apiKeys"].(string) + if apiKeys != "" { + var apiKeysStruct ApiKeyTypes + json.Unmarshal([]byte(ConfigParams["apiKeys"].(string)), &apiKeysStruct) + req.Header.Set("X-API-KEY", apiKeysStruct.ApproverToken[0]) + } + req.Header.Set("Content-Type", "application/json") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return nil, res.StatusCode, err + } + defer res.Body.Close() + + body, err := io.ReadAll(res.Body) + if err != nil { + return nil, res.StatusCode, err + } + + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { + return body, res.StatusCode, fmt.Errorf("status: %d, body: %s", res.StatusCode, body) + } + + return body, res.StatusCode, err +} diff --git a/testHelpers/test_config.go b/testHelpers/test_config.go new file mode 100644 index 0000000..b55e030 --- /dev/null +++ b/testHelpers/test_config.go @@ -0,0 +1,27 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +// Map with all required parameters needed to access TSB +var ConfigParams map[string]interface{} = map[string]interface{}{ + "restapi": "TSB_API_URL", + "auth": "TOKEN", + "bearertoken": "TSB_BEARER_TOKEN", +} diff --git a/testHelpers/test_functions.go b/testHelpers/test_functions.go new file mode 100644 index 0000000..dedb69d --- /dev/null +++ b/testHelpers/test_functions.go @@ -0,0 +1,740 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package testHelpers + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-hclog" + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vault/sdk/helper/logging" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + "securosys.ch/backend" +) + +type TestEnv struct { + Backend logical.Backend + Context context.Context + Storage logical.Storage +} + +var keyPair *rsa.PrivateKey = nil + +// Function checking that 2 variables are equals +func AreEqual(x, y interface{}) (bool, error) { + xv := reflect.ValueOf(x) + yv := reflect.ValueOf(y) + if yv.Type().ConvertibleTo(xv.Type()) { + return xv.Interface() == yv.Convert(xv.Type()).Interface(), nil + } else { + return false, errors.New("Types are mismatched") + } +} +func InitRSAKeyPair() { + keyPair, _ = rsa.GenerateKey(rand.Reader, 2048) +} +func Sign(data []byte) string { + msgHash := sha256.New() + msgHash.Write(data) + msgHashSum := msgHash.Sum(nil) + signature, _ := rsa.SignPKCS1v15(rand.Reader, keyPair, crypto.SHA256, msgHashSum) + signatureBase64 := base64.StdEncoding.EncodeToString(signature) + return signatureBase64 +} +func GetPublicKey() string { + pub := keyPair.Public() + asn1Bytes, _ := x509.MarshalPKIXPublicKey(pub) + // Encode private key to PKCS#1 ASN.1 PEM. + pubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: asn1Bytes, + }, + ) + publicKey := string(pubPEM[:]) + publicKey = strings.Replace(publicKey, "-----BEGIN PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "-----END PUBLIC KEY-----", "", 1) + publicKey = strings.Replace(publicKey, "\n", "", 20) + return publicKey +} + +// This function create initialized test enviornment with storage in memory +func NewTestEnv() (*TestEnv, error) { + ctx := context.Background() + + maxLease, _ := time.ParseDuration("99999s") + defaultLease, _ := time.ParseDuration("88888s") + conf := &logical.BackendConfig{ + System: &logical.StaticSystemView{ + DefaultLeaseTTLVal: defaultLease, + MaxLeaseTTLVal: maxLease, + }, + Logger: logging.NewVaultLogger(log.Debug), + } + b, err := backend.Factory(ctx, conf) + if err != nil { + return nil, err + } + return &TestEnv{ + Backend: b, + Context: ctx, + Storage: &logical.InmemStorage{}, + }, nil +} + +// Function initialize configuration needed by all functions/operations on keys in TSB +func (e *TestEnv) AddConfig(t *testing.T) { + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: e.Storage, + Data: ConfigParams, + } + _, err := e.Backend.HandleRequest(e.Context, req) + require.Nil(t, err) +} + +// Function prepare some test keys +func (e *TestEnv) PrepareTestKeys(t *testing.T) { + InitRSAKeyPair() + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_256_rotate", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_ROTATE_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/aes/test_aes_128", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/bls/test_bls", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/camellia/test_camellia", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/chacha20/test_chacha20", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/dsa/test_dsa_1024", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ec/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/ed/test_ed_ed25519", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/test_tdea", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": true,"sensitive": false,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_pass", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_PASS_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_modify", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_MODIFY_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/rsa/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_POLICY_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "simplePolicy": `{"Tomasz Madej":"` + GetPublicKey() + `"}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + //Create key using Hashicorp Vault Key Management key types + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/aes256-gcm96/type_aes", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-2048/type_rsa_2048", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-3072/type_rsa_3072", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/rsa-4096/type_rsa_4096", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_RSA_4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p256/type_ec_p256", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P256_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p384/type_ec_p384", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P384_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/ecdsa-p521/type_ec_p521", + Data: map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TYPE_EC_P521_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } +} + +// Function deletes test keys +func (e *TestEnv) RemoveTestKeys(t *testing.T) { + _, err := e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_128", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_bls", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_camellia", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_chacha20", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_dsa_1024", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ec_secp256k1", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_ed_ed25519", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + _, err = e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_tdea", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_modify", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_pass", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_rsa_2048_policy", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_aes", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_2048", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_3072", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_rsa_4096", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p256", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p384", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + time.Sleep(1000) + e.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/type_ec_p521", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: e.Storage, + }) + if err != nil { + fmt.Println(err.Error()) + } + +} + +// Function preparing a testing backend system +func GetTestBackend(tb testing.TB) (*backend.SecurosysBackend, logical.Storage) { + tb.Helper() + + config := logical.TestBackendConfig() + config.StorageView = new(logical.InmemStorage) + config.Logger = hclog.NewNullLogger() + config.System = logical.TestSystemView() + + b, err := backend.Factory(context.Background(), config) + if err != nil { + tb.Fatal(err) + } + + return b.(*backend.SecurosysBackend), config.StorageView +} + +// Function thats make a request for delete key operation +func TestKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for create key operation +func TestKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string, keyType string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyType + "/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +// Function thats make a request for reading key xml data +func TestKeyReadXML(t *testing.T, b logical.Backend, s logical.Storage, expected []string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName + "/xml", + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for _, expectedV := range expected { + actualV, ok := resp.Data[expectedV] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, expectedV, expectedV) + } + if actualV == "" || actualV == nil { + return fmt.Errorf(`expected data["%s"] = is not empty`, expectedV) + } + } + + return nil +} + +// Function thats make a request for reading key data +func TestKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..8a47046 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,66 @@ +module securosys.ch/tests + +replace securosys.ch/test-helpers => ./../testHelpers + +replace securosys.ch/backend => ./../backend + +replace securosys.ch/client => ./../client + +replace securosys.ch/helpers => ./../helpers + +go 1.19 + +require ( + github.com/hashicorp/vault/sdk v0.9.1 + github.com/stretchr/testify v1.8.4 + securosys.ch/helpers v0.0.0-00010101000000-000000000000 + securosys.ch/test-helpers v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/andreburgaud/crypt2go v1.2.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + securosys.ch/backend v0.0.0-00010101000000-000000000000 // indirect + securosys.ch/client v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/tests/go.sum b/tests/go.sum new file mode 100644 index 0000000..adcd319 --- /dev/null +++ b/tests/go.sum @@ -0,0 +1,223 @@ +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE= +github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/vault/sdk v0.9.1 h1:fMkjCfqC5ohA2b7p1kv5poe488pFhBl9oaz2FkDkDAQ= +github.com/hashicorp/vault/sdk v0.9.1/go.mod h1:YmQ899tcCpwEgH6fOfU7AY0OURy8EqYj8sEdRac25TM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tests/go.work b/tests/go.work new file mode 100644 index 0000000..7c33c4f --- /dev/null +++ b/tests/go.work @@ -0,0 +1,5 @@ +go 1.21 + +use ( + ./ +) \ No newline at end of file diff --git a/tests/go.work.sum b/tests/go.work.sum new file mode 100644 index 0000000..a8e4e74 --- /dev/null +++ b/tests/go.work.sum @@ -0,0 +1,182 @@ +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= diff --git a/tests/path_config_test.go b/tests/path_config_test.go new file mode 100644 index 0000000..5f6878b --- /dev/null +++ b/tests/path_config_test.go @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestConfig(t *testing.T) { + b, reqStorage := testHelpers.GetTestBackend(t) + + t.Run("Test Configuration", func(t *testing.T) { + err := testConfigCreate(t, b, reqStorage, testHelpers.ConfigParams) + + if err != nil { + assert.FailNow(t, err.Error()) + } + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": testHelpers.ConfigParams["restapi"], + "auth": testHelpers.ConfigParams["auth"], + }) + + assert.NoError(t, err) + + err = testConfigUpdate(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + "bearertoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwcmltdXNkZXYiLCJ2ZXIiOjEsIm5iZiI6MTY2NDU0NzE0NSwib25ib2FyZFBhcnRpdGlvbiI6InRydWUiLCJpc3MiOiJTZWN1cm9zeXMgQ2xvdWQgQXV0aG9yaXphdGlvbiBTZXJ2aWNlIERFViIsInBhdFRTQiI6InBoakVWQllcL3Zadzd5N3gwWW1XQklUZWg5V3FGOTc0dVdNYTZPWDJiTDJoV0ZLTTg3MGdqTE1xOHZCU0R3ZUpTbWUxS1JSSllSXC9DOVlDXC85MUg2RndWTXZtOFhGcDRodlpuNlhKVkRvcDMyc1BHNTV1NmFCSzJzbGRJVnJaYTRDRThcL2NBZ0xVbVlubmZoZWZLRHVHalBYNWRHV25GUWRVWWVVakpaN1c0TDVkS2RDckNZUHpsZmRuU1BcL0p1YytsWGdlcm1JaWVtRVZDZGt1R043WWl4ZnIxM2FOaiIsImV4cCI6MzMyMjE0OTkxNDUsImlhdCI6MTY2NDU0NzE0NSwibm9uY2UiOnsic2FsdCI6IjNubzAxdTdlNDhoSEUwdUs3M1N3R3c9PSIsIml2IjoiUTlKZGxFT1R0Uyt1NjR6QiJ9fQ.DWoebl3J4ItyYWLU3uBlHxXROuLRtUi1vGsHzsn5ebZbQv_MDFwIcxl8sTJ_sOM1u5bU6wDRfEl3iphuq6KZiHik-PM7LsIsHtYmw-mIaqy1q05zjmVmamQW24fzzn-Doiwuv1PzxnekUOdS3hoV-M57_2RHzHriBAQWgN0B7mE-gz-TIEKDq9haXkw9swg9j9h-QFGhEcHfiayb8gISZIM_DRBC3a4ne5llxHl5yDvMXv8Ibxg8X8dv3HmG8KCJGZrts90R9fFDkJwUvEAiByDqq6rWzteN_feUrXR4loZvPJl05EV4dvHXIU26UAL_0HtfEReCdiwrmnebJITLKw", + }) + + assert.NoError(t, err) + + err = testConfigRead(t, b, reqStorage, map[string]interface{}{ + "restapi": "https://primusdev.cloudshsm.com", + "auth": "TOKEN", + }) + + assert.NoError(t, err) + + err = testConfigDelete(t, b, reqStorage) + + assert.NoError(t, err) + }) +} + +func testConfigDelete(t *testing.T, b logical.Backend, s logical.Storage) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigUpdate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "config", + Data: d, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testConfigRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "config", + Storage: s, + }) + + if err != nil { + return err + } + + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output"`, k, expectedV) + } else if expectedV != actualV { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v"`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_aes_test.go b/tests/path_hsm_key_aes_test.go new file mode 100644 index 0000000..1895454 --- /dev/null +++ b/tests/path_hsm_key_aes_test.go @@ -0,0 +1,133 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestAESKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating AES key = KeySize 256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_256", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_256_" + timeStr, + "keySize": 256, + "algorithm": "AES", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_256") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 192", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_192", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_192_" + timeStr, + "keySize": 192, + "algorithm": "AES", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_192") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + } + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_192") + assert.NoError(t, err) + + }) + t.Run("Test Creating AES key = KeySize 128", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_aes_128", "aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_AES_128_" + timeStr, + "keySize": 128, + "algorithm": "AES", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_aes_128") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes_128") + assert.NoError(t, err) + + }) +} diff --git a/tests/path_hsm_key_bls_test.go b/tests/path_hsm_key_bls_test.go new file mode 100644 index 0000000..a8c6069 --- /dev/null +++ b/tests/path_hsm_key_bls_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestBLSKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating BLS key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": true,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_bls", "bls") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_BLS_" + timeStr, + "keySize": 256, + "algorithm": "BLS", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_bls") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_bls") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_camellia_test.go b/tests/path_hsm_key_camellia_test.go new file mode 100644 index 0000000..aa148a5 --- /dev/null +++ b/tests/path_hsm_key_camellia_test.go @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCamelliaKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CAMELLIA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_camellia", "camellia") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CAMELLIA_" + timeStr, + "keySize": 256, + "algorithm": "Camellia", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_camellia") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_camellia") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_chacha20_test.go b/tests/path_hsm_key_chacha20_test.go new file mode 100644 index 0000000..02ae5a8 --- /dev/null +++ b/tests/path_hsm_key_chacha20_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCHACHA20Key(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating CHACHA20 key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_chacha20", "chacha20") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_CHACHA20_" + timeStr, + "keySize": 256, + "algorithm": "ChaCha20", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_chacha20") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_chacha20") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_dsa_test.go b/tests/path_hsm_key_dsa_test.go new file mode 100644 index 0000000..629bcb3 --- /dev/null +++ b/tests/path_hsm_key_dsa_test.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestDSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating DSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_1024", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "DSA", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating DSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_dsa_2048", "dsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_DSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "DSA", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_dsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_dsa_2048") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ec_test.go b/tests/path_hsm_key_ec_test.go new file mode 100644 index 0000000..d073797 --- /dev/null +++ b/tests/path_hsm_key_ec_test.go @@ -0,0 +1,134 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestECKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating EC key = curveOid secp256k1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp256k1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp256k1_" + timeStr, + "curveOid": "1.3.132.0.10", + "algorithm": "EC", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp256k1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_") + } + + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp256k1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid secp384r1", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_secp384r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_secp384r1_" + timeStr, + "curveOid": "1.3.132.0.34", + "algorithm": "EC", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_secp384r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_secp384r1") + + assert.NoError(t, err) + }) + t.Run("Test Creating EC key = curveOid (prime256v1 / secp256r1)", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ec_prime256v1_secp256r1", "ec") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_EC_prime256v1_secp256r1_" + timeStr, + "curveOid": "1.2.840.10045.3.1.7", + "algorithm": "EC", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ec_prime256v1_secp256r1") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + } + assert.NoError(t, err) + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ec_prime256v1_secp256r1") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_ed_test.go b/tests/path_hsm_key_ed_test.go new file mode 100644 index 0000000..fc17f02 --- /dev/null +++ b/tests/path_hsm_key_ed_test.go @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestEDKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating ED key = curveOid Ed25519", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "curveOid": "1.3.101.112", + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_ed_ed25519", "ed") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ED_Ed25519_" + timeStr, + "algorithmOid": "1.3.101.112", + "algorithm": "ED", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_ed_ed25519") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ed_ed25519") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_import_test.go b/tests/path_hsm_key_import_test.go new file mode 100644 index 0000000..7d4c8e8 --- /dev/null +++ b/tests/path_hsm_key_import_test.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIMPORTKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating IMPORT key = AES", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testIMPORTKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + "secretKey": "SkBOY1JmVWpYbjJyNXU3eCFBJUQqRy1LYVBkU2dWa1k=", + "algorithm": "AES", + }, "custom_import_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_IMPORT_AES_" + timeStr, + "algorithm": "AES", + "keySize": 256, + }, "custom_import_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_import_aes") + + assert.NoError(t, err) + }) +} + +func testIMPORTKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/" + keyName + "/import", + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_key_rsa_test.go b/tests/path_hsm_key_rsa_test.go new file mode 100644 index 0000000..3630d20 --- /dev/null +++ b/tests/path_hsm_key_rsa_test.go @@ -0,0 +1,166 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRSAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating RSA key = KeySize 1024", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_1024", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_1024_" + timeStr, + "keySize": 1024, + "algorithm": "RSA", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_1024") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_1024") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "algorithm": "RSA", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_3072", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_3072_" + timeStr, + "keySize": 3072, + "algorithm": "RSA", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating RSA key = KeySize 4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_4096", "rsa") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_4096_" + timeStr, + "keySize": 4096, + "algorithm": "RSA", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + err = testHelpers.TestKeyReadXML(t, testEnv.Backend, testEnv.Storage, []string{ + "xml", "keyLabel", "xmlSignature", + }, "custom_rsa_4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_4096") + + assert.NoError(t, err) + }) +} diff --git a/tests/path_hsm_key_tdea_test.go b/tests/path_hsm_key_tdea_test.go new file mode 100644 index 0000000..56229c0 --- /dev/null +++ b/tests/path_hsm_key_tdea_test.go @@ -0,0 +1,136 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestTDEAKey(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating TDEA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testTDEAKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 0, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_tdea") + + assert.NoError(t, err) + + err = testTDEAKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_TDEA_" + timeStr, + "keySize": 192, + "algorithm": "TDEA", + }, "custom_tdea") + if err != nil { + testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + } + assert.NoError(t, err) + + err = testTDEAKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_tdea") + + assert.NoError(t, err) + }) +} + +func testTDEAKeyDelete(t *testing.T, b logical.Backend, s logical.Storage, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/" + keyName, + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: s, + }) + + if err != nil { + return err + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/tdea/" + keyName, + Data: d, + Storage: s, + }) + + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} + +func testTDEAKeyRead(t *testing.T, b logical.Backend, s logical.Storage, expected map[string]interface{}, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/" + keyName, + Storage: s, + }) + + if err != nil { + return err + } + if resp == nil && expected == nil { + return nil + } + + if resp.IsError() { + return resp.Error() + } + + for k, expectedV := range expected { + actualV, ok := resp.Data[k] + if !ok { + return fmt.Errorf(`expected data["%s"] = %v but was not included in read output`, k, expectedV) + } + result, err := testHelpers.AreEqual(expectedV, actualV) + if err != nil { + return fmt.Errorf(`unexpected error: %s`, err.Error()) + } + if !result { + return fmt.Errorf(`expected data["%s"] = %v, instead got %v`, k, expectedV, actualV) + } + } + + return nil +} diff --git a/tests/path_hsm_key_using_type_name_test.go b/tests/path_hsm_key_using_type_name_test.go new file mode 100644 index 0000000..06d847e --- /dev/null +++ b/tests/path_hsm_key_using_type_name_test.go @@ -0,0 +1,245 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestCreateKeyUsingTypeName(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + + t.Run("Test Creating Key with type name = aes256-gcm96", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "aes256-gcm96", "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_aes256-gcm96_" + timeStr, + "algorithm": "AES", + "keySize": 256, + "keyTypeName": "aes256-gcm96", + }, "custom_aes256-gcm96_aes") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_aes256-gcm96_aes") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-2048", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-2048", "custom_rsa-2048") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-2048_" + timeStr, + "algorithm": "RSA", + "keySize": 2048, + "keyTypeName": "rsa-2048", + }, "custom_rsa-2048") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-2048") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-3072", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-3072", "custom_rsa-3072") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-3072_" + timeStr, + "algorithm": "RSA", + "keySize": 3072, + "keyTypeName": "rsa-3072", + }, "custom_rsa-3072") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-3072") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = rsa-4096", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "rsa-4096", "custom_rsa-4096") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_rsa-4096_" + timeStr, + "algorithm": "RSA", + "keySize": 4096, + "keyTypeName": "rsa-4096", + }, "custom_rsa-4096") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa-4096") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p256", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p256", "custom_ecdsa-p256") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p256_" + timeStr, + "algorithm": "EC", + "curveOid": "1.2.840.10045.3.1.7", + "keyTypeName": "ecdsa-p256", + }, "custom_ecdsa-p256") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p256") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p384", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p384", "custom_ecdsa-p384") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p384_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.34", + "keyTypeName": "ecdsa-p384", + }, "custom_ecdsa-p384") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p384") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = ecdsa-p521", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p521", "custom_ecdsa-p521") + + assert.NoError(t, err) + + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "baseLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p521_" + timeStr, + "algorithm": "EC", + "curveOid": "1.3.132.0.35", + "keyTypeName": "ecdsa-p521", + }, "custom_ecdsa-p521") + if err != nil { + testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + } + assert.NoError(t, err) + + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_ecdsa-p521") + + assert.NoError(t, err) + }) + t.Run("Test Creating Key with type name = that is not supported", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testKeyUsingNameCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_ecdsa-p921_" + timeStr, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "ecdsa-p921", "custom_ecdsa-p921") + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error: 'Key type name ecdsa-p921 is not supported. Available key type names [aes256-gcm96 rsa-2048 rsa-3072 rsa-4096 ecdsa-p256 ecdsa-p384 ecdsa-p521]', but error is nil")) + } + + }) + +} + +func testKeyUsingNameCreate(t *testing.T, b logical.Backend, s logical.Storage, d map[string]interface{}, keyTypeName string, keyName string) error { + resp, err := b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "keys/type/" + keyTypeName + "/" + keyName, + Data: d, + Storage: s, + }) + if err != nil { + return fmt.Errorf(err.Error()) + } + + if resp != nil && resp.IsError() { + return resp.Error() + } + return nil +} diff --git a/tests/path_hsm_keys_rotation_test.go b/tests/path_hsm_keys_rotation_test.go new file mode 100644 index 0000000..d0a44f5 --- /dev/null +++ b/tests/path_hsm_keys_rotation_test.go @@ -0,0 +1,836 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestRotateKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Rotate Key - AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_aes_256", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_bls", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_bls/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_bls") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_bls", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_bls", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_camellia", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_camellia") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_camellia", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_camellia", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_chacha20") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_chacha20", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_chacha20", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_dsa_1024/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_dsa_1024") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_dsa_1024", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_dsa_1024", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ec_secp256k1/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ec_secp256k1") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ec_secp256k1", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ec_secp256k1", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_ed_ed25519/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_ed_ed25519") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_ed_ed25519", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_ed_ed25519", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - TDEA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_tdea", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_tdea") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_tdea", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_tdea", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - RSA with Policy", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_policy") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_rsa_2048_policy", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "test_rsa_2048_policy", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT AES256-GCM96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_aes", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_aes") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_aes", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_aes", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-2048", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_2048") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_2048", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_2048", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-3072", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_3072/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_3072") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_3072", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_3072", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT RSA-4096", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_4096/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_rsa_4096") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_rsa_4096", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_rsa_4096", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p256", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p256/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p256") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p256", err.Error())) + + } + if key.CurrentVersion != "v3" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p256", key.CurrentVersion)) + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p384/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p384") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p384", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p384", key.CurrentVersion)) + + } + + }) + t.Run("Test Rotate Key - HASHICORP VAULT ECDSA-P521", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v2" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_ec_p521/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "type_ec_p521") + if err != nil { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "type_ec_p521", err.Error())) + + } + if key.CurrentVersion != "v3" { + + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v3' got '%s'", "type_ec_p521", key.CurrentVersion)) + + } + + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_keys_test.go b/tests/path_hsm_keys_test.go new file mode 100644 index 0000000..6e9f56e --- /dev/null +++ b/tests/path_hsm_keys_test.go @@ -0,0 +1,312 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + backend "securosys.ch/backend" + testHelpers "securosys.ch/test-helpers" +) + +func TestKeys(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test keys list", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/", + Storage: testEnv.Storage, + }) + if len(resp.Data["keys"].([]string)) < 11 { + assert.FailNow(t, fmt.Sprintf("Expected 11 keys, but got %d", len(resp.Data["keys"].([]string)))) + + } + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Export Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_camellia/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_chacha20/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_tdea/export", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Register Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_2/register", + Data: map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + }, + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256_2") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Read Keys", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256", + Storage: testEnv.Storage, + }) + err = testHelpers.TestKeyRead(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": resp.Data["keyLabel"], + "keySize": resp.Data["keySize"], + "algorithm": resp.Data["algorithm"], + }, "test_aes_256") + + if err != nil { + assert.FailNow(t, err.Error()) + } + + }) + t.Run("Test Block Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == false { + assert.FailNow(t, fmt.Sprintf("Key %s is not blocked!", "test_rsa_2048_modify")) + } + }) + t.Run("Test UnBlock Keys", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + if key.GetActiveVersion().Policy.KeyStatus.Blocked == true { + assert.FailNow(t, fmt.Sprintf("Key %s is blocked!", "test_rsa_2048_modify")) + } + + }) + t.Run("Test Modify Keys", func(t *testing.T) { + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if err != nil { + assert.FailNow(t, err.Error()) + } + groupsLenBefore := len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_modify/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err = backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_modify") + if groupsLenBefore == len(key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups) { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy", "test_rsa_2048")) + } + if *key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Name != "MICHAL NOWAK" && key.GetActiveVersion().Policy.RuleUse.Tokens[0].Groups[0].Approvals[0].Value != "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB" { + assert.FailNow(t, fmt.Sprintf("Modify for the %s was not changed policy. Expected approval name MICHAL NOWAK", "test_rsa_2048")) + } + + }) + t.Run("Test Rotate Keys", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_aes_256_rotate/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + key, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_aes_256_rotate") + if err != nil { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Got error: %s", "test_aes_256_rotate", err.Error())) + + } + if key.CurrentVersion != "v2" { + assert.FailNow(t, fmt.Sprintf("Rotate not working for the %s key. Expected key version 'v2' got '%s'", "test_aes_256_rotate", key.CurrentVersion)) + + } + + }) + t.Run("Test Key Version List", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) < 2 { + assert.FailNow(t, fmt.Sprintf("Expected 2 key versions, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Read Key Version v2", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["version"] != "v2" { + assert.FailNow(t, fmt.Sprintf("Wrong key version. Expected v2 got %s", resp.Data["version"])) + } + + }) + t.Run("Test Key Delete Version - Active", func(t *testing.T) { + _, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v2", + Storage: testEnv.Storage, + }) + if err == nil { + assert.FailNow(t, fmt.Sprintf("Expected error on deleting current active key version")) + } + + }) + t.Run("Test Key Delete Version", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/test_aes_256_rotate/v1", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "keys/test_aes_256_rotate/", + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if len(resp.Data["keys"].([]string)) != 1 { + assert.FailNow(t, fmt.Sprintf("Expected 1 key version, but got %d", len(resp.Data["keys"].([]string)))) + } + + }) + t.Run("Test Update Password", func(t *testing.T) { + _, err := backend.Backend().GetKey(context.Background(), testEnv.Storage, "test_rsa_2048_pass") + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_pass/update-password", + Data: map[string]interface{}{ + "password": "", + "newPassword": "pass", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_decrypt_test.go b/tests/path_hsm_operations_decrypt_test.go new file mode 100644 index 0000000..fc6d519 --- /dev/null +++ b/tests/path_hsm_operations_decrypt_test.go @@ -0,0 +1,1001 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsDecrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Decrypt AES - cipher AES", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256/v1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": "v2", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - before rotate - cipher AES_GCM - 96", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/type_aes", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_GCM", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_GCM - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_GCM - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher CTR", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CTR - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - cipher ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt AES - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + + assert.Error(t, err) + + }) + + t.Run("Test Decrypt - No encryptedPayload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "encryptedPayload": "test", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt RSA - wrong payload. Expected '%s' got '%s'", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcGF5bG9hZA", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CHACHA20 - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_TEST", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt CAMELLIA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_CBC_NO_PADDING - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + + }) + t.Run("Test Decrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "keyVersion": "v1", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - cipher TDEA_ECB - %s", err.Error())) + } + if resp.Data["payload"] != "cGF5bG9hZA==" { + assert.FailNow(t, fmt.Sprintf("Error on decrypt TDEA - wrong payload. Expected '%s' got '%s'", "cGF5bG9hZA==", resp.Data["payload"])) + } + }) + t.Run("Test Decrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "keyVersion": "v1", + "encryptedPayload": "ELfKnNiGDj3cI74XYSLQEA==", + "initializationVector": "waDAws/4fsRjf420RVq5Hg==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_encrypt_test.go b/tests/path_hsm_operations_encrypt_test.go new file mode 100644 index 0000000..b83f0c3 --- /dev/null +++ b/tests/path_hsm_operations_encrypt_test.go @@ -0,0 +1,505 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsEncrypt(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Encrypt AES - cipher AES", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - after rotate - cipher AES_GCM - 96", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_aes/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/type_aes", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_GCM", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": -1, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher CTR", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CTR", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CTR - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - cipher AES_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt AES - cipher AES_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt AES - wrong AES cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt AES - wrong tagLength ", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "tagLength": 256, + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + + t.Run("Test Encrypt - No payload", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong payload format", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "asasasa", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key name", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_2562", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - Wrong key algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_ec_secp256k1", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - No cipher algorithm", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt - wrong AAD ", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_aes_256", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES_GCM", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "wrong_base64", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA224", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA224 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA256", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA256 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA1", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA1 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA384", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA384 - %s", err.Error())) + } + }) + t.Run("Test Encrypt RSA - cipher RSA_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20_AEAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20_AEAD", + "payload": "cGF5bG9hZA==", + "additionalAuthenticationData": "QWRkaXRpb25hbCBBdXRoZW50aWNhdGlvbiBEYXRh", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20_AEAD - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - cipher CHACHA20", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "CHACHA20", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CHACHA20 - cipher CHACHA20 - %s", err.Error())) + } + }) + t.Run("Test Encrypt CHACHA20 - wrong CHACHA20 cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_chacha20", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_CBC_NO_PADDING - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - cipher CAMELLIA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "CAMELLIA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt CAMELLIA - wrong CAMELLIA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_camellia", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_CBC_NO_PADDING", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_CBC_NO_PADDING", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - cipher TDEA_ECB", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "TDEA_ECB", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt CAMELLIA - cipher CAMELLIA_ECB - %s", err.Error())) + } + }) + t.Run("Test Encrypt TDEA - wrong TDEA cipher algorithm", func(t *testing.T) { + + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_tdea", + Data: map[string]interface{}{ + "cipherAlgorithm": "AES", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + assert.Error(t, err) + + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_sign_test.go b/tests/path_hsm_operations_sign_test.go new file mode 100644 index 0000000..74b64c2 --- /dev/null +++ b/tests/path_hsm_operations_sign_test.go @@ -0,0 +1,647 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsSign(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Sign EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + }) + t.Run("Test Sign ED - signature EDDSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature NONE_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + }) + t.Run("Test Sign RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // }) + // t.Run("Test Sign RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + }) + // t.Run("Test Sign RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // }) + t.Run("Test Sign RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature NONE_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + }) + t.Run("Test Sign DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + }) + // t.Run("Test Sign ISS - signature ISS_KERL", func(t *testing.T) { + // _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // }) + t.Run("Test Sign BLS - signature BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_unwrap_test.go b/tests/path_hsm_operations_unwrap_test.go new file mode 100644 index 0000000..e93a9d3 --- /dev/null +++ b/tests/path_hsm_operations_unwrap_test.go @@ -0,0 +1,675 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsUnWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test UnWrap AES - wrap method AES_WRAP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP - alternative", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256/v1", + Data: map[string]interface{}{ + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_DSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_EC", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_ED", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_RSA", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_aes_256", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "AES_WRAP_PAD_BLS", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - rotate key after wrap - wrap method RSA_WRAP_PAD", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_PAD", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("Test UnWrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unwrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "keys/unwraped_key_test", + Data: map[string]interface{}{"removeFromHSM": true}, + Storage: testEnv.Storage, + }) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_verify_test.go b/tests/path_hsm_operations_verify_test.go new file mode 100644 index 0000000..a0faf3c --- /dev/null +++ b/tests/path_hsm_operations_verify_test.go @@ -0,0 +1,1438 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsVerify(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Verify EC - signature NONE_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature NONE_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature NONE_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA1_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA1_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA1_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA256_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA384_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert. + NoError(t, fmt.Errorf("Error on sign EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA512_WITH_ECDSA - signature is not valid") + } + + }) + t.Run("Test Verify EC - signature SHA3224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature SHA3512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA3512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature SHA3512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature SHA3512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK224_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK224_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK224_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK224_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK256_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK256_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK256_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK256_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK384_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK384_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK384_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK384_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify EC - signature KECCAK512_WITH_ECDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ec_secp256k1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ec_secp256k1", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "KECCAK512_WITH_ECDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify EC - signature KECCAK512_WITH_ECDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify EC - signature KECCAK512_WITH_ECDSA - signature is not valid") + } + }) + t.Run("Test Verify ED - signature EDDSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_ed_ed25519", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign ED - signature EDDSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_ed_ed25519", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "EDDSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify ED - signature EDDSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify ED - signature EDDSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature NONE_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature NONE_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature NONE_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA224_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA224_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA224_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA256_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA256_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA256_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA384_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA384_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA384_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA512_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA512_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA512_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify DSA - signature SHA1_WITH_DSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_dsa_1024", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_dsa_1024", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_DSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify DSA - signature SHA1_WITH_DSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify DSA - signature SHA1_WITH_DSA - signature is not valid") + } + }) + t.Run("Test Verify BLS - signature BLS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_bls", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign BLS - signature BLS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_bls", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "BLS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify BLS - signature BLS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify BLS - signature BLS - signature is not valid") + } + }) + // t.Run("Test Verify ISS - signature ISS_KERL", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign ISS - signature ISS_KERL - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_iss_1", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "ISS_KERL", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify ISS - signature ISS_KERL - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify ISS - signature ISS_KERL - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA_PSS - alternative", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048/v1", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA_PSS - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature NONE_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "NONE_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONE_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature NONE_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA256_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA256_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA256_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA256_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA384_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA384_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA384_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA384_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - signature SHA512_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA512_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA512_WITH_RSA - signature is not valid") + } + }) + t.Run("Test Verify RSA - rotate key - signature SHA224_WITH_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + + t.Run("Test Verify RSA - rotate key after signature - signature SHA224_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/type_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/type_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA224_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA224_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA224_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA224_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA224_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA224_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA224_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA256_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA256_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA256_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA256_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA384_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA384_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA384_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA384_WITH_RSA - signature is not valid") + // } + // }) + // t.Run("Test Verify RSA - signature NONESHA512_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA512_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA512_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA512_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA - signature is not valid") + } + }) + // t.Run("Test Verify RSA - signature NONESHA1_WITH_RSA", func(t *testing.T) { + // resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/sign/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + // Operation: logical.UpdateOperation, + // Path: "operation/verify/test_rsa_2048", + // Data: map[string]interface{}{ + // "payloadType": "UNSPECIFIED", + // "payload": "cGF5bG9hZA==", + // "signatureAlgorithm": "NONESHA1_WITH_RSA", + // "signature": resp.Data["signature"], + // }, + // Storage: testEnv.Storage, + // }) + // if err != nil { + // assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature NONESHA1_WITH_RSA - %s", err.Error())) + // } + // if resp.Data["signatureValid"].(bool) == false { + // assert.FailNow(t, "Error on verify RSA - signature NONESHA1_WITH_RSA - signature is not valid") + // } + // }) + t.Run("Test Verify RSA - signature SHA1_WITH_RSA_PSS", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/verify/test_rsa_2048", + Data: map[string]interface{}{ + "keyVersion": "v1", + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA1_WITH_RSA_PSS", + "signature": resp.Data["signature"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on verify RSA - signature SHA1_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["signatureValid"].(bool) == false { + assert.FailNow(t, "Error on verify RSA - signature SHA1_WITH_RSA_PSS - signature is not valid") + } + }) + + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_operations_wrap_test.go b/tests/path_hsm_operations_wrap_test.go new file mode 100644 index 0000000..97a2cff --- /dev/null +++ b/tests/path_hsm_operations_wrap_test.go @@ -0,0 +1,242 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestOperationsWrap(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Wrap AES - wrap method AES_WRAP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_DSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_dsa_1024/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_DSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_DSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_EC", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ec_secp256k1/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_EC", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_EC - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_ED", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_ed_ed25519/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_ED", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_ED - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_RSA", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_rsa_2048/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_RSA", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_RSA - %s", err.Error())) + } + }) + t.Run("Test Wrap AES - wrap method AES_WRAP_PAD_BLS", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_bls/test_aes_256", + Data: map[string]interface{}{ + "wrapMethod": "AES_WRAP_PAD_BLS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap AES - wrap method AES_WRAP_PAD_BLS - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - rotate key - wrap method RSA_WRAP_PAD", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/type_rsa_2048/rotate", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/type_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_PAD", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_PAD - %s", err.Error())) + } + }) + t.Run("Test Wrap RSA - wrap method RSA_WRAP_OAEP", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} diff --git a/tests/path_hsm_requests_test.go b/tests/path_hsm_requests_test.go new file mode 100644 index 0000000..5fb5051 --- /dev/null +++ b/tests/path_hsm_requests_test.go @@ -0,0 +1,301 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestRequests(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("add config", testEnv.AddConfig) + t.Run("prepare test keys", testEnv.PrepareTestKeys) + t.Run("Test Create async operation - decrypt", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/encrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "payload": "cGF5bG9hZA==", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on encrypt RSA - cipher RSA_PADDING_OAEP_WITH_SHA512 - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/decrypt/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512", + "encryptedPayload": resp.Data["encryptedPayload"], + "initializationVector": resp.Data["initializationVector"], + "messageAuthenticationCode": resp.Data["messageAuthenticationCode"], + }, + Storage: testEnv.Storage, + }) + if err != nil { + if resp != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + } + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "Decrypt" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Decrypt") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unwrap", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/wrap/test_aes_128/test_rsa_2048_policy", + Data: map[string]interface{}{ + "wrapMethod": "RSA_WRAP_OAEP", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on wrap RSA - wrap method RSA_WRAP_OAEP - %s", err.Error())) + } + resp, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/unwrap/unwraped_key_test/test_rsa_2048_policy", + Data: map[string]interface{}{ + "keyVersion": resp.Data["keyVersion"], + "keyLabel": "unwraped_key_test_" + timeStr, + "wrappedKey": resp.Data["wrappedKey"], + "wrapMethod": "RSA_WRAP_OAEP", + "attributes": `{"decrypt": true,"sign": true,"unwrap": true,"derive": false,"sensitive": true,"extractable": false,"modifiable": true,"destroyable": true}`, + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, err.Error()) + } + if resp.Data["type"].(string) != "UnWrap" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnWrap") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - sign", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "operation/sign/test_rsa_2048_policy", + Data: map[string]interface{}{ + "payloadType": "UNSPECIFIED", + "payload": "cGF5bG9hZA==", + "signatureAlgorithm": "SHA512_WITH_RSA_PSS", + }, + Storage: testEnv.Storage, + }) + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on sign RSA - signature SHA512_WITH_RSA_PSS - %s", err.Error())) + } + if resp.Data["type"].(string) != "Sign" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Sign") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - block", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/block", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on block RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Block" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Block") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - unblock", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/unblock", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on unblock RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "UnBlock" { + assert.FailNow(t, err.Error()) + } + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("UnBlock") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("Test Create async operation - modify", func(t *testing.T) { + resp, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.UpdateOperation, + Path: "keys/test_rsa_2048_policy/modify", + Data: map[string]interface{}{ + "simplePolicy": `{"MICHAL NOWAK":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouyYMgsCbxdr6cN7EDIR4ZcB82/fAIZusqyNXpX6gcRTwnrxZfIlyATdAm7ascxgYIK+L2M9UFVKTPUxus/Hzfuq0Fro5tdH+DWwfYQtcB5vap3UTw3yNpi6/MUe1x1Odwwi3no3jE2OuF1k6wjyrbWBkyktF3g8BmOD0DFpGl4IIlE8u1NgOMyAzlIuzAiyl4aCHrddhfV6gFtrRqfpUMz0twXYYoHlK0khzVEVn757WZZcIQFZmjKMfp/Yl/CAkBrTGVnFHMmNOYq7L9vhoR71rPmU9u2sy6IaT97qox/e7HSW47N2YNSiuJeq08I3Tn/kyw6+pSjAMu4A48PrfQIDAQAB","TOMMAD":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXglPuzN4MeMxkSptpmXK2klFGiGCODDVR1gM7ykxdc/JIQ2IPmA0Dq1a0ERNTVlFWhXNCWVUzSoWZ0St4hA+GMB8ZA1n9pM8V/e8RP6ej0aCBOfbOan7Q9GuHvs08RBF29hqsoVAFyAOoCxfs0Dv26Eb+PQgtPl6hTYjcSUVqWfHPoTjm+L6jLvdoFtE02muPon8Vno3wb9aGy1GYn/2ZSDtYg8HYV6Due7XKBJbmOMt5S6UHxc5Q+94v6xdjjijYM8sR1E7Hm4dTlocg4vlIHOXIdjFqSJlx87t21a+hyLEk15VjQUsKvUSu/jKTr4MvZwqar6EwGYRRCdwdWD1QIDAQAB"}`, + }, + Storage: testEnv.Storage, + }) + + if err != nil { + assert.FailNow(t, fmt.Sprintf("Error on modify RSA - %s", err.Error())) + } + if resp.Data["type"].(string) != "Modify" { + assert.FailNow(t, err.Error()) + } + + client, _ := testHelpers.NewTestTSBClient() + id, approvalToBeSigned, _ := client.GetApprovalTasks("Modify") + client.MakeApproval(id, approvalToBeSigned) + result, err := testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "requests/" + resp.Data["id"].(string), + Storage: testEnv.Storage, + }) + if err != nil { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, err.Error()) + } + // result + status := result.Data["status"].(string) + if status != "EXECUTED" { + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + assert.FailNow(t, fmt.Sprintf("Wrong status of request. Expected EXECUTED got %s", result.Data["status"].(string))) + } + removeRequest(t, testEnv.Backend, testEnv.Storage, resp.Data["id"].(string)) + }) + t.Run("remove test keys", testEnv.RemoveTestKeys) + +} +func removeRequest(t *testing.T, b logical.Backend, s logical.Storage, id string) { + b.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "requests/" + id, + Data: map[string]interface{}{}, + Storage: s, + }) + +} diff --git a/tests/path_mariadb_integration_test.go b/tests/path_mariadb_integration_test.go new file mode 100644 index 0000000..b9b856e --- /dev/null +++ b/tests/path_mariadb_integration_test.go @@ -0,0 +1,111 @@ +/* +Copyright (c) 2023 Securosys SA, authors: Tomasz Madej + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +*/ + +package tests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/assert" + testHelpers "securosys.ch/test-helpers" +) + +func TestIntegrationMariaDB(t *testing.T) { + testEnv, err := testHelpers.NewTestEnv() + if err != nil { + t.Fatal(err) + } + t.Run("A) add config", testEnv.AddConfig) + + t.Run("B) Test Creating RSA key", func(t *testing.T) { + now := time.Now().UTC() + timeStr := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02dZ", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()) + err := testHelpers.TestKeyCreate(t, testEnv.Backend, testEnv.Storage, map[string]interface{}{ + "keyLabel": "TEST_SECUROSYS_SECRETS_ENGINE_RSA_2048_" + timeStr, + "keySize": 2048, + "attributes": `{"decrypt": true,"sign": false,"unwrap": true,"derive": true,"sensitive": false,"extractable": false,"modifiable": true,"copyable": false,"destroyable": true}`, + }, "custom_rsa_2048", "rsa") + + assert.NoError(t, err) + + }) + t.Run("C)Add generate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("D)Read secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ReadOperation, + Path: "integrations/mariadb/test/v1?key_name=custom_rsa_2048&cipher_algorithm=RSA", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("E) Rotate secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.CreateOperation, + Path: "integrations/mariadb/test", + Data: map[string]interface{}{ + "keyName": "custom_rsa_2048", + "cipherAlgorithm": "RSA", + }, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("F) List secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.ListOperation, + Path: "integrations/mariadb", + Data: map[string]interface{}{}, + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("G) Delete secret", func(t *testing.T) { + _, err = testEnv.Backend.HandleRequest(context.Background(), &logical.Request{ + Operation: logical.DeleteOperation, + Path: "integrations/mariadb/test", + Storage: testEnv.Storage, + }) + assert.NoError(t, err) + + }) + t.Run("H) Test Delete RSA key", func(t *testing.T) { + err = testHelpers.TestKeyDelete(t, testEnv.Backend, testEnv.Storage, "custom_rsa_2048") + assert.NoError(t, err) + }) +}